Stephanie Eckles2024-01-20T00:00:00.000Zhttps://thinkdobecreate.comStephanie EcklesA Call for Consensus on HTML Semantics2024-01-20T00:00:00.000Zhttps://thinkdobecreate.com/articles/a-call-for-consensus-on-html-semantics/
<p>HTML is supposed to be easy to learn. And sure, the basics are pretty clear, like when to use a <code>p</code> over an <code>a</code>. (But, lol, watch out for when to use <code>a</code> vs <code>button</code>)</p><p>There are several scenarios I think will plague me til the end of my webdev days, especially with a push towards components and templates that are to assume a consistent hierarchy (ha!) particularly when aiding dynamic and/or user-generated content but should also be accessible, scalable, maintainable, and provide an inclusive user experience. Woof.</p><p>Perhaps you want to build something that seems simple on the surface, like a blog. Suddenly you are faced with some gray-area scenarios, such as:</p><ul><li>Should the author bio photo be a <code>figure</code> or just an <code>img</code>?</li><li>Markdown blockquotes are convenient for creating “callouts”, but should some (most?) of those actually be just decorated paragraphs or even <code><aside role=”note”></code>?</li><li>The sidebar is showing categories of things with headings but do those headings really need promoted to an <code>h2</code> just to keep the heading hierarchy in order? Or should they be a nested list structure with the “title” text styled bold? Or… is there a secret third option?</li><li>A table of contents of the article structure <code>feels</code> better as a right-hand sidebar, but then it’s either more obnoxious for keyboard-only users to get to it since they may have to tab the entire article content first, or if it lives prior to the article in the DOM but visually is on the right then you break the logical tab order for sighted keyboard users. So, is it destined to be structurally and visually on the left-hand side?</li><li>And if you do add a table of contents, how is it treated for narrow viewports? Displayed before the article as an expanded list or collapsed? Or a duplicated version if you chose to structurally place it after the article for wider viewports? Ugh… what a mess…</li><li>How much do we need to fret about putting the published date in a <code>time</code> or using <code>cite</code> for referenced resources? What other micro elements are we forgetting that might improve someone's experience?</li></ul><p>Or heck, let’s back up and examine the home page, too.</p><ul><li>Starting out we’ve got a <code>nav</code> and then we have a “hero” which seems like it should be a <code>header</code> but… at what point does the “header” content become overly complex and need to be broken into another element?</li><li>There should only be one <code>main</code> per HTML document, and all content should be contained in a <code>landmark</code> element, but if we need to take some content out of the <code>header</code> then what should it live in if it’s also not quite <code>main</code>? An <code>aside</code>? An <code>article</code>?</li><li>Those groups of marketing fluff - are those best as an <code>article</code> or a <code>section</code>, knowing that <code>section</code> is <a href="https://www.scottohara.me/blog/2021/07/16/section.html" rel="noopener noreferrer">not meaningfully exposed to assistive technology by default</a> so it often might as well be a <code>div</code>, and an <code>article</code> is supposed to contain content that could theoretically make sense standing alone outside the context of the rest of the page. So, should we just do <code>div</code> after <code>div</code> within <code>main</code> and call it good and worry more about things like the heading hierarchy?</li><li>Should testimonials be in a <code>figure</code> or a <code>blockquote</code> or… both? (Honestly, when the heck should we even use <code>figure</code> or <code>blockquote</code> in general… does anyone really know? 😅)</li></ul><p>You'll find a few opinions on each of these things (particularly <code>section</code> vs <code>article</code>) but my point is that it's never clear cut and certainly not simple.</p><p>Oh look, a dashboard has entered the chat.</p><ul><li>lol, give up now, here there be dragons, abandon all hope, ye who enter here</li></ul><p>(But really, start with your landmarks, and work to deeply understand your workflows, content hierarchy, and users before you simply choose an off-the-shelf component with no semantic flexibility, mmmk?)</p><p>WHO HAS THESE ANSWERS? WE’RE ALL JUST DOING OUR BEST! AND NOW WE HAVE TO DEAL WITH AI PRETENDING TO BE OMNISCIENT AND DELIVERING CONFIDENTLY WRONG ANSWERS TO MILLIONS OF DEVS OF ALL SKILL LEVELS HOW WILL WE EVER GET IT RIGHT IS HUMANITY DOOMED TO BECOME AN ABLEIST HELLSCAPE WHAT EVEN IS THE WEB.</p><p>Ahem. Pardon me. </p><p>All this to say... HTML markup is a skill that is honed in the fires of experience that may be learned but never mastered, but it is an honorable and worthy battle.</p><p>Please help.</p><p>(Also, you should hire front-of-the-front-end specialists who actually care about these nuances and accessibility specialists to help jump these hurdles and ux researchers to put in the work and find out about your real users and and and… don’t rely on AI, please. Pretty pretty please.)</p>
Simplified Dark Mode With Style Queries2023-02-27T00:00:00.000Zhttps://thinkdobecreate.com/articles/simplified-dark-mode-with-style-queries/
<p>Style queries are an extended part of <a href="https://www.w3.org/TR/css-contain-3/" target="_blank" rel="noopener noreferrer">the containment spec</a> which container queries also came from. <strong>TL;DR:</strong> they allow you to query for style features of a container and apply rules to its children. </p><p>For example, if the <code>--theme</code> custom property has the value <code>dark</code>, then you can style child elements with a dark theme. This specific ability to query custom property values is available as of Chromium 111. If you're reading prior to March 7, you'll want to visit the demos in Chrome Canary.</p><p>So, how does that help us simplify defining dark mode styles?</p><p>Here's the "old" way if you needed to support both user preference <em>and</em> a setting from a theme toggle:</p><pre class="language-css"><code class="language-css"><span class="token comment">/* User preference */</span><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">body</span> <span class="token punctuation">{</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">/* Set via JS or server-side post form submit */</span><br /><span class="token selector">body[data-theme="dark"]</span> <span class="token punctuation">{</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre><p>The duplication of the style blocks is necessary because there is no way to combine a selector with a media query.</p><p>However, with style queries, we can modify our setup and only write the dark theme/mode styles once!</p><p>Unlike the need to define containment for size container queries to work, all elements are inherently style containers. This means we can use style queries against any element without an extra step! </p><p>So, for both of the conditions we previously had for the user preference and custom data attribute, we'll simply set the custom property of <code>--theme</code>. Following that, our style query picks up that value and applies the dark theme styles.</p><pre class="language-css"><code class="language-css"><span class="token comment">/* User preference */</span><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">html</span> <span class="token punctuation">{</span><br /> <span class="token property">--theme</span><span class="token punctuation">:</span> dark<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">/* Set via JS or server-side post form submit */</span><br /><span class="token selector">html[data-theme="dark"]</span> <span class="token punctuation">{</span><br /> <span class="token property">--theme</span><span class="token punctuation">:</span> dark<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">/* Attach dark mode styles */</span><br /><span class="token atrule"><span class="token rule">@container</span> <span class="token function">style</span><span class="token punctuation">(</span><span class="token property">--theme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">body</span> <span class="token punctuation">{</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre><aside role="note"><p>Both style and size container queries cannot update properties on the container, so that's why we are styling <code><body></code> since it is the child of <code><html> </code>which is being queried for the value of <code>--theme</code>.</p></aside><p>You can certainly specify styles for light mode as well, or flip the logic if your site defaults to a dark theme. A reminder that this isn't production-ready today, but it may be at least a progressive enhancement candidate towards the end of 2023!</p><p class="codepen" data-default-tab="css,result" data-slug-hash="XWPpWZj" data-preview="true" data-user="5t3ph"></p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script><div class="heading-wrapper h2">
<h2 id="learn-more-about-style-queries">Learn more about style queries</h2>
<a href="https://thinkdobecreate.com/articles/simplified-dark-mode-with-style-queries/#learn-more-about-style-queries" aria-labelledby="learn-more-about-style-queries">
<span hidden="">#</span>
</a></div><p>Una shows examples to <a href="https://developer.chrome.com/blog/style-queries/" target="_blank" rel="noopener noreferrer">get started with style queries</a>, and notes the outstanding issues that will help make the spec even more powerful. I also recommend her earlier personal post with even <a href="https://una.im/style-queries/" target="_blank" rel="noopener noreferrer">more examples of style queries</a>. Another outstanding resource is Ahmad Shadeed's overview of <a href="https://ishadeed.com/article/css-container-style-queries/" target="_blank" rel="noopener noreferrer">use cases for style queries</a>.</p>
Is It Time To Replace Sass?2023-02-25T00:00:00.000Zhttps://thinkdobecreate.com/articles/is-it-time-to-replace-sass/
<p>I have used Sass for a very long time within marketing departments, design system teams, and on many solo projects. My standout reasons <a href="https://thinkdobecreate.com/articles/in-defense-of-sass/" rel="noopener noreferrer">as expanded upon in this post</a> were:</p><ul><li>file organization</li><li>list and maps</li><li>looping</li><li>static variable overrides</li></ul><p>See how "nesting" didn't even make that list (even though it absolutely is a feature I'm accustomed to using)? Meanwhile, it seemed like a significant portion of my network heard "native CSS nesting is coming!" and immediately declared Sass was dead.</p><p>So... what is available in the meantime before nesting is fully stable and has significant browser support? And what other features do we miss out on by moving from Sass?</p><div class="heading-wrapper h2">
<h2 id="all-in-on-lightningcss">All In on LightningCSS</h2>
<a href="https://thinkdobecreate.com/articles/is-it-time-to-replace-sass/#all-in-on-lightningcss" aria-labelledby="all-in-on-lightningcss">
<span hidden="">#</span>
</a></div><p>I became a fan of <a href="https://lightningcss.dev/" rel="noopener noreferrer">LightningCSS</a> very soon after it was released. It's a parser for CSS that autoprefixes, minifies, and transpiles new CSS (including nesting) to accommodate your browser targets.</p><p>While I had already swapped to using LightningCSS primarily for minification and autoprefixing in my <a href="https://github.com/5t3ph/11ty-sass-skeleton" rel="noopener noreferrer">Eleventy Sass starter</a>, including releasing <a href="https://github.com/5t3ph/eleventy-plugin-sass-lightningcss" rel="noopener noreferrer">a dedicated plugin</a>, I recently evaluated if I needed Sass at all. You can also get the non-Sass <a href="https://github.com/5t3ph/eleventy-plugin-lightningcss" rel="noopener noreferrer">LightningCSS Eleventy Plugin</a>.</p><div class="heading-wrapper h3">
<h3 id="feature-comparison">Feature Comparison</h3>
<a href="https://thinkdobecreate.com/articles/is-it-time-to-replace-sass/#feature-comparison" aria-labelledby="feature-comparison">
<span hidden="">#</span>
</a></div><p>Your priorities may be different, but here is what I considered as features I would need to be supported in order to replace Sass.</p><ul><li><strong>nesting</strong> - yup, covered during transpiling as long as you <a href="https://lightningcss.dev/transpilation.html#nesting" rel="noopener noreferrer">enable the nesting option</a> or include the CLI flag</li><li><strong>compile from separate files</strong> - yes, uses the <a href="https://lightningcss.dev/bundling.html#%40import" rel="noopener noreferrer"><code>@import</code> syntax</a> and already supports defining imports as layers!</li><li><strong>static variables</strong> - not without <a href="https://lightningcss.dev/transforms.html#unknown-at-rules" rel="noopener noreferrer">a custom at-rule transform</a>, but I've largely moved to use custom properties, so this would have low impact for most of my projects</li><li><strong>looping</strong> - no, but potentially possible to work out as a custom transform?</li><li><strong>lists and maps</strong> - no, and also not as useful without looping available</li><li><strong>mixins</strong> - again, <a href="https://lightningcss.dev/transforms.html#custom-at-rules" rel="noopener noreferrer">mixins are possible</a> via custom transforms and actually the example given in the docs</li><li><strong>complex custom functions</strong> - Sass is likely still going to win unless you want to build your functions in Node etc. first</li><li><strong>build integration</strong> - <a href="https://lightningcss.dev/docs.html" rel="noopener noreferrer">CLI and methods for Node</a> and other build tools is available, as well as already being built-in to Parcel</li><li><strong>single-line comments</strong> - fans of <code>// comments</code> will have to stick to Sass for support OOTB (honestly, I will miss this, too)</li></ul><p>Additional features that I find beneficial from switching to LightningCSS for CSS processing:</p><ul><li>minification</li><li>autoprefixing</li><li><a href="https://lightningcss.dev/transpilation.html" rel="noopener noreferrer">transpiling/"syntax lowering"</a> of particularly nesting, media range queries, logical properties, and new color functions and features like relative color syntax</li></ul><aside role="note"><p>Be sure to <a href="https://lightningcss.dev/transpilation.html#browser-targets" rel="noopener noreferrer">setup browser targets</a> or autoprefixing and transpiling will not occur.</p></aside><div class="heading-wrapper h2">
<h2 id="will-i-keep-using-sass">Will I Keep Using Sass?</h2>
<a href="https://thinkdobecreate.com/articles/is-it-time-to-replace-sass/#will-i-keep-using-sass" aria-labelledby="will-i-keep-using-sass">
<span hidden="">#</span>
</a></div><p>Yes, but for a shrinking set of reasons which revolve around making large projects that are intended to have downstream customization (think: multi-brand/team design systems). Then again, I might nerd-snipe myself and make LightningCSS plugins to fill the gaps. Or perhaps... one of you reading will make them? Or point out a tool I haven't heard of yet?</p><p>I enjoy building or customizing my own tooling where needed, but if that doesn't appeal to you, then sticking with Sass may be the best option. Even then, you may find LightningCSS is a swap for stringing together multiple PostCSS plugins like it was for me.</p>
My CSS Wishlist 20232023-02-19T00:00:00.000Zhttps://thinkdobecreate.com/articles/css-wishlist-2023/
<p>The amount of stuff that has landed in CSS in the past few years is kind of mind-boggling, and difficult to keep up with! Other folks have been posting the (impressively small, all things considered) list of things they've wished for, so I decided to join in. The other wishlists I know of to date are in the last section.</p><div class="heading-wrapper h2">
<h2 id="my-wishlist">My Wishlist</h2>
<a href="https://thinkdobecreate.com/articles/css-wishlist-2023/#my-wishlist" aria-labelledby="my-wishlist">
<span hidden="">#</span>
</a></div><p>One reason <a href="https://thinkdobecreate.com/articles/in-defense-of-sass/" rel="noopener noreferrer">I continue to use Sass</a> is to use loops. And, part of the reason for that is scenarios where I want access to the index of the thing I'm styling, like dynamic <code>nth-child</code> rules. Recently Kevin Pennekamp showed off a trick of <a href="https://crinkles.dev/writing/a-nth-child-css-trick/" rel="noopener noreferrer">hacking around getting an index</a> by setting global custom properties against <code>nth-child</code> selectors. </p><p>My wish is for an actual <code>index</code> keyword that is available as a number so that it can be used in the types of scenarios Kevin describes, like within <code>calc()</code>, color functions, transforms, opacity, and more.</p><pre class="language-css"><code class="language-css"><span class="token comment">/* Alternating background colors if `index` existed */</span><br /><span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span>60 * index<span class="token punctuation">)</span> 80% 60%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><aside role="note"><p>Worth noting that Safari and soon-to-release Chromium 111 has the <a href="https://developer.chrome.com/articles/css-nth-child-of-s/" rel="noopener noreferrer">of S syntax for nth-child</a> that allows <code>nth</code> selections based on a selector (such as a class), which is also pretty great for dealing with numbers of things.</p></aside><p>The last frontier in providing reasonably cross-browser custom form controls is <a href="https://codepen.io/5t3ph/pen/LYzwrLr" rel="noopener noreferrer">inheritably resizable checkboxes and radio buttons</a>. Presently you can apply a custom size in Chromium and Firefox, but Safari prohibits resizing, leading folks to still create <a href="https://moderncss.dev/pure-css-custom-styled-radio-buttons/" rel="noopener noreferrer">complete style overrides</a>.</p><p>Did you know an easy way to <a href="https://codepen.io/5t3ph/pen/abmBwza" rel="noopener noreferrer">achieve gradient borders</a> is with <code>border-image</code>? Unfortunately, once you apply <code>border-image</code>, you're forced into a square corner appearance, so my wish is to retain <code>border-radius</code> when using <code>border-image</code>.</p><p>Finally, while we have <code>::before</code> and <code>::after</code>, I'm looking for a not-so-secret third (and fourth) thing, like perhaps <code>::box-before</code> and <code>::box-after</code>. The before and after pseudo-elements are basically treated like inline text by default until you introduce your own positioning. They also count towards the accessible name for some assistive tech and browser combos, and they are sometimes an extra focus stop for Narrator (the Windows screen reader). This causes problems when trying to use them not as content at all, but as decorative flourishes which is what I'm actually after 90% or more of the time. </p><p>While I think two <code>::box-</code> pseudo-elements may be enough for me, Jim Nielsen takes a different angle and requests <a href="https://blog.jim-nielsen.com/2023/css-wishlist/#me-unlimited-pseudo-elements" rel="noopener noreferrer">unlimited pseudo-elements</a>. Maybe we could meet in the middle with a <code>::box</code> pseudo-element that accepts an index kind of like <code>nth-child,</code> so it could be overridden later?</p><pre class="language-css"><code class="language-css">.<span class="token property">element</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">box</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><br />.<span class="token property">element</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">box</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span></code></pre><div class="heading-wrapper h3">
<h3 id="noted-in-other-wishlists">Noted in Other Wishlists</h3>
<a href="https://thinkdobecreate.com/articles/css-wishlist-2023/#noted-in-other-wishlists" aria-labelledby="noted-in-other-wishlists">
<span hidden="">#</span>
</a></div><p>Here are some things others have wished for that are definitely a priority for me as well:</p><ul><li>A way to <a href="https://ishadeed.com/article/css-wishlist-2023/#detect-when-sticky-is-active" rel="noopener noreferrer">detect when sticky position is active</a> (ripe for the plucking when style container queries mature) from Ahmad Shadeed</li><li>Also from Ahmad is the clever idea for <a href="https://ishadeed.com/article/flex-wrap-detect/" rel="noopener noreferrer">flex-wrap detection</a>, an idea which he expanded into an article</li><li>CSS OG Eric Meyer requests <a href="https://meyerweb.com/eric/thoughts/2023/02/08/css-wish-list-2023/#more-attr" rel="noopener noreferrer">extending attr() for more contexts</a> than the content property, such as for widths, and I would love it for <code>calc()</code> and so many other things that I've forgotten at this point. It's really one of those things that make you hit your head against your desk when you have the perfect use case, and it doesn't work.</li><li><a href="https://cloudfour.com/thinks/tylers-css-wish-list-for-2023/" rel="noopener noreferrer">Line wrap balancing</a> was noted by Tyler Sticka, which would prevent orphans and be far more robust than using <code><br></code> which breaks down (pun intended) when dealing with international content or really any responsive design</li></ul><div class="heading-wrapper h2">
<h2 id="already-on-the-csswg-radar">Already on the CSSWG Radar</h2>
<a href="https://thinkdobecreate.com/articles/css-wishlist-2023/#already-on-the-csswg-radar" aria-labelledby="already-on-the-csswg-radar">
<span hidden="">#</span>
</a></div><p>The following are also high on my wishlist, and are being worked on with partial support in canary/nightly builds or at least movement in the specs.</p><ul><li>responsive queries based on custom variable values can be achieved with <a href="https://una.im/style-queries/" rel="noopener noreferrer">style container queries</a> (Chrome 111) and recently resolved was to allow <a href="https://front-end.social/@mia/109633918145314350" rel="noopener noreferrer">length custom property values in size container queries</a>, too</li><li><a href="https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/" rel="noopener noreferrer">relative color syntax</a> is the magical ability to transform a color into a new color, available so far in Safari 16.4</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-contrast" rel="noopener noreferrer"><code>color-contrast()</code> is a proposed function</a> to dynamically have the browser select the color with appropriate contrast from a list of palette options (no browser support yet)</li><li><code>leading-trim</code> fixes that annoying issue of the mystery space above/below single-line text, like in a button as <a href="https://twitter.com/shadeed9/status/1624092817814429697" rel="noopener noreferrer">brilliantly demonstrated by Ahmad Shadeed</a>, currently only in Safari Tech Preview and <a href="https://twitter.com/Una/status/1624155693912580100" rel="noopener noreferrer">Una cautions its at risk</a> of a name change</li><li><code>margin-trim</code> provides <a href="https://www.matuzo.at/blog/2023/100daysof-day96/" rel="noopener noreferrer">control over removing leftover margin space</a> as explained by Manuel Matuzović, currently only in Safari Tech Preview</li><li><a href="https://drafts.csswg.org/css-display-4/#display-order" rel="noopener noreferrer">display order</a> is an active CSSWG issue to address the mismatch that can occur between the tabbing order of elements that have been re-arranged visually via the <code>order</code> property of flex or grid</li></ul><div class="heading-wrapper h2">
<h2 id="recently-made-possible">Recently Made Possible</h2>
<a href="https://thinkdobecreate.com/articles/css-wishlist-2023/#recently-made-possible" aria-labelledby="recently-made-possible">
<span hidden="">#</span>
</a></div><p>In the last couple of years, long-standing issues I have encountered many times over my 15+ year career were resolved.</p><ul><li><a href="https://www.smashingmagazine.com/2021/05/complete-guide-css-container-queries/" rel="noopener noreferrer">container queries</a> to orchestrate layout changes relative to the container instead of the viewport</li><li><a href="https://www.smashingmagazine.com/2023/01/level-up-css-skills-has-selector/" rel="noopener noreferrer">parent/ancestor/sibling selections</a> became possible with :has()</li><li>shorthand for bilateral margin and padding can be done with the logical properties of <code>margin-inline</code> or <code>padding-inilne</code> which sets the left/right at once (in a horizontal writing mode) as well as <code>margin-block</code> or <code>padding-block</code> to set the top/bottom at once (in a horizontal writing mode)</li><li><a href="https://12daysofweb.dev/2022/2022-css-updates/#custom-form-control-colors-with-accent-color" rel="noopener noreferrer">themable form controls</a> are possible for a subset of types including checkboxes, radio buttons, range input, and progress using the <code>accent-color</code> property</li><li><a href="https://web.dev/css-individual-transform-properties/" rel="noopener noreferrer">individual transform properties</a> arrived to separately set <code>scale</code>, <code>rotate</code>, and <code>translate</code></li><li>As of Safari 16.4, the <code>outline</code> property will follow the <code>border-radius</code> across browsers (meaning it will also be rounded instead of keeping square corners)</li></ul><div class="heading-wrapper h2">
<h2 id="other-wishlists">Other Wishlists</h2>
<a href="https://thinkdobecreate.com/articles/css-wishlist-2023/#other-wishlists" aria-labelledby="other-wishlists">
<span hidden="">#</span>
</a></div><p>Be sure to peruse the lists of these other folks, and consider making your own!</p><ul><li><a href="https://daverupert.com/2023/01/css-wishlist-2023/" rel="noopener noreferrer">Dave Rupert</a></li><li><a href="https://ishadeed.com/article/css-wishlist-2023/" rel="noopener noreferrer">Ahmad Shadeed</a></li><li><a href="https://chriscoyier.net/2022/12/21/things-css-could-still-use-heading-into-2023/" rel="noopener noreferrer">Chris Coyier</a></li><li><a href="https://meyerweb.com/eric/thoughts/2023/02/08/css-wish-list-2023/" rel="noopener noreferrer">Eric Meyer</a></li><li><a href="https://cloudfour.com/thinks/tylers-css-wish-list-for-2023/" rel="noopener noreferrer">Tyler Sticka</a></li><li><a href="https://www.matuzo.at/blog/2023/css-wish-list/" rel="noopener noreferrer">Manuel Matuzović</a></li><li><a href="https://blog.mayank.co/my-css-wishlist-2023" rel="noopener noreferrer">Mayank</a></li><li><a href="https://blog.jim-nielsen.com/2023/css-wishlist/" rel="noopener noreferrer">Jim Nielsen</a></li></ul>
My 2022 In Review2022-12-30T00:00:00.000Zhttps://thinkdobecreate.com/articles/my-2022-in-review/
<p>2022 was a year of some personal changes. We moved to a new house, and my two kids started public school. Both of those things zapped a lot of my energy for several months and led to apathy toward web stuff. But it was a net gain for my mental health as we have improved our access to accommodations, and feel less on top of each other as a family. I'm finally feeling a little more energized and motivated to get back to projects, and have several things to look forward to in 2023!</p><div class="heading-wrapper h2">
<h2 id="conference-talks">Conference talks</h2>
<a href="https://thinkdobecreate.com/articles/my-2022-in-review/#conference-talks" aria-labelledby="conference-talks">
<span hidden="">#</span>
</a></div><p>The accomplishment I'm most proud of this past year is speaking at my first in-person, international conference - <strong>beyond tellerrand</strong> in May. If you missed it, here are slides, the video recording, and other resources for the talk "<a href="https://noti.st/st3ph/YWbRfR/scaling-css-layout-beyond-pixels" rel="noopener noreferrer">Scaling CSS Layout Beyond Pixels</a>."</p><ul><li>Practical Uses For Container Queries at <strong>Web Directions: Hover</strong></li><li><a href="https://youtu.be/dCBZIsFl8s8?t=603" rel="noopener noreferrer">User Zoom and Reflow</a> at<code> </code><strong>Accessibility Club </strong>- don't miss the other talks in the meetup recording as well!</li><li><a href="https://www.deque.com/axe-con/sessions/modern-css-upgrades-to-improve-accessibility/" rel="noopener noreferrer">Modern CSS Upgrades to Improve Accessibility</a> at <strong>axe-con 2022 </strong>(create a free account to view the recording)</li><li>The Modern CSS Toolkit at <strong>Stay Curious (BT) - </strong><a href="https://codepen.io/5t3ph/pen/LYzvrGv" rel="noopener noreferrer">interactive slides</a> available on CodePen</li></ul><p>I have two international conference talks lined up so far for 2023 (details TBA), and a few virtual appearances as well. I'm looking to fill more of my calendar, so <a href="https://thinkdobecreate.com/contact/" rel="noopener noreferrer">get in touch</a> if you're looking for speakers about front-end, CSS, 11ty, or accessibility!</p><p>First up in January will be <a href="https://cfe.dev/events/the-jam-2023/" rel="noopener noreferrer">TheJam.dev conference</a> - virtual and free this year!</p><div class="heading-wrapper h2">
<h2 id="writing">Writing</h2>
<a href="https://thinkdobecreate.com/articles/my-2022-in-review/#writing" aria-labelledby="writing">
<span hidden="">#</span>
</a></div><p>Writing took a little bit of a lower priority this year, but it continues to be something I enjoy doing and already have several articles in the works to kickoff 2023.</p><ul><li><a href="https://www.smashingmagazine.com/2022/01/introduction-css-cascade-layers/" rel="noopener noreferrer">Getting Started With CSS Cascade Layers</a></li><li><a href="https://moderncss.dev/contextual-spacing-for-intrinsic-web-design/" rel="noopener noreferrer">Contextual Spacing For Intrinsic Web Design</a></li><li><a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/" rel="noopener noreferrer">4 Required Tests Before Shipping New Features</a></li><li><a href="https://thinkdobecreate.com/articles/in-defense-of-sass/" rel="noopener noreferrer">In Defense of Sass</a></li><li><a href="https://thinkdobecreate.com/articles/dev-content-creation-journey/" rel="noopener noreferrer">My Dev Content Creation Journey and Tips for Starting Yours</a></li><li><a href="https://thinkdobecreate.com/articles/css-animating-newly-added-element/" rel="noopener noreferrer">CSS Quick Tip: Animating in a newly added element</a></li><li><a href="https://thinkdobecreate.com/articles/minimum-static-site-sass-setup/" rel="noopener noreferrer">Minimum Static Site Setup with Sass</a></li><li><a href="https://12daysofweb.dev/2022/dialog/" rel="noopener noreferrer">HTML Dialog</a></li><li><a href="https://12daysofweb.dev/2022/pointer-events/" rel="noopener noreferrer">Pointer Events</a></li><li><a href="https://12daysofweb.dev/2022/2022-css-updates/" rel="noopener noreferrer">2022 CSS Updates</a></li></ul><p>I also share some of the ideas via my newsletter before turning them into an article, so <a href="https://moderncss.dev/newsletter/" rel="noopener noreferrer">be sure to subscribe</a>!</p><div class="heading-wrapper h2">
<h2 id="projects">Projects</h2>
<a href="https://thinkdobecreate.com/articles/my-2022-in-review/#projects" aria-labelledby="projects">
<span hidden="">#</span>
</a></div><p>I announced that I was creating <strong><a href="https://challenges.moderncss.dev/" rel="noopener noreferrer">Modern CSS Challenges</a></strong> this year, and unfortunately I didn't make as much progress on it as I hoped. It is my priority to finish in early 2023, so sign up to be notified when it's available.</p><p>I created <a href="https://reposwrapped.dev/stats/5t3ph/2022/" rel="noopener noreferrer">ten new repos</a> this year, some of which were related to Twitch streams or to help repro a bug, or otherwise in an incomplete state.</p><p>One project I was excited about was to create a package called <strong><a href="https://github.com/5t3ph/css-browser-support" rel="noopener noreferrer">css-browser-support</a></strong>. Use it to query for CSS browser support data, combined from caniuse and MDN, including version support started and global support percentages. There's also a <a href="https://github.com/5t3ph/eleventy-plugin-css-browser-support" rel="noopener noreferrer">companion 11ty plugin</a> which allows you to display either a popover showing support for a single property, or a table of multiple properties.</p><p>I use CodePen often for article demos or just trying things out. Here is a collection of four pens showing <a href="https://codepen.io/collection/zxpyrd" rel="noopener noreferrer">a few fun CSS tricks</a>.</p><p>The final project of the year - officially the second annual - was <strong><a href="https://12daysofweb.dev/" rel="noopener noreferrer">12 Days of Web</a></strong>. This year, 9 incredible guest authors contributed, and I'm so thankful they shared their time and expertise. Visit the series to learn from the authors including: Eric Meyer, Miriam Suzanne, Kevin Powell, Adam Argyle, Rachel Andrew, Estelle Weyl, Chris Ferdinandi, Ryan Trimble, and Evan Sheehan.</p><div class="heading-wrapper h2">
<h2 id="looking-to-2023">Looking to 2023</h2>
<a href="https://thinkdobecreate.com/articles/my-2022-in-review/#looking-to-2023" aria-labelledby="looking-to-2023">
<span hidden="">#</span>
</a></div><p>As mentioned, I have a few articles in-progress, some conferences on the calendar, and will be committed to finishing Modern CSS Challenges.</p><p>I'm also eager for the CSS features that landed this year to have wider support and to begin using more of them in my projects! So look for more resources exploring those.</p><p>See you around the web, particularly <a href="https://twitch.tv/5t3phDev" rel="noopener noreferrer">on Twitch</a>, and <a href="https://front-end.social/@5t3ph" rel="noopener noreferrer">on Mastodon</a>, and maybe at some conferences. Happy New Year!</p>
4 Required Tests Before Shipping New Features2022-10-07T00:00:00.000Zhttps://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/
<p>Sure your feature passed the unit tests, and QA says it's good to go - but is it? To really be sure, here are four types of tests that are best to consider critical to every feature from the start. Include these tests to improve the accessibility of your features and assist your users in successfully completing tasks.</p><div class="heading-wrapper h2">
<h2 id="color-contrast">Color Contrast</h2>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#color-contrast" aria-labelledby="color-contrast">
<span hidden="">#</span>
</a></div><p>Yes, this old chestnut again - the truly lowest-hanging fruit that you can pick and improve for any feature release. You may feel you've heard enough about it, but clearly, as a collective, we aren't doing a great job actually following through on ensuring color contrast of our interfaces. The WebAIM Million report from 2022 found <a href="https://webaim.org/projects/million/#wcag" rel="noopener noreferrer">text color contrast issues on 83.9% of home pages</a> tested, making it the top detected error.</p><p>The minimum contrast ratios for WCAG AA are defined as:</p><ul><li>4.5:1 for normal text</li><li>3:1 for large text - defined as 18.66px <strong>and</strong> bold or larger, or 24px and larger</li><li>3:1 for graphics and user interface components (such as form input borders)</li></ul><aside role="note"><p><strong>Head's up:</strong> A new color contrast model called APCA is being considered for WCAG 3, but it will be a few years before it becomes the standard. It's best to stick to the current model until the updates are final, especially since there can be some legal obligations based on WCAG 2.x depending on industry or country regulations.</p></aside><p>Color contrast checking is available for design tools, across dev tools, and via many online tools. I also enjoy this Mac desktop tool, <a href="https://contrasteapp.com/" rel="noopener noreferrer">Contraste App</a> that can pick colors for comparison from any window on your screen.</p><p>It is fairly easily detectable by automated tools, too, such as the following browser plugins:</p><ul><li><a href="https://wave.webaim.org/extension/" rel="noopener noreferrer">WAVE from WebAIM</a> (used to generate the report)</li><li><a href="https://www.deque.com/axe/browser-extensions/" rel="noopener noreferrer">axe</a></li><li><a href="https://accessibilityinsights.io/downloads/" rel="noopener noreferrer">Accessibility Insights</a> FastPass (uses axe-core with additional features)</li></ul><p>Some of my favorite online tools for checking and choosing color contrast:</p><ul><li><a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer">WebAIM Contrast Checker</a></li><li><a href="https://contrast-finder.tanaguru.com/" rel="noopener noreferrer">tanaguru contrast finder</a> - helps find the next-closest matches to create a contrasting pair</li><li><a href="https://contrast-ratio.com/" rel="noopener noreferrer">contrast ratio</a> - a simple visual checker to test contrast pairs and updates to a unique URL</li><li><a href="https://colourcontrast.cc/" rel="noopener noreferrer">Colour Contrast Checker</a> - another web app but with controls to adjust your colors and creates a unique URL to share, also available as a browser extension</li></ul><p>To address precisely the challenge of ensuring an accessible color palette more efficiently, I've created the package <a href="https://www.npmjs.com/package/a11y-color-tokens" rel="noopener noreferrer">a11y-color-tokens</a>.</p><div class="heading-wrapper h3">
<h3 id="interactive-element-color-contrast">Interactive Element Color Contrast</h3>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#interactive-element-color-contrast" aria-labelledby="interactive-element-color-contrast">
<span hidden="">#</span>
</a></div><p>We often focus on text contrast, so the part about the contrast of user interface components is often forgotten. Particularly tricky is the contrast across states of interactive elements. For example, buttons may have five contrast considerations!</p><p class="block-img"><img src="https://images.prismic.io/tdbc/5f2447b3-ee7a-440f-9d16-aea5ba1d1db7_button-contrast.jpeg?auto=compress,format" alt="An infographic showing a "default" button that is midrange shade of purple with white letters next to its "focus" state which is a darker purple. Icons and labels show that the contrast of the default purple to the light yellow page background is 4.17, from the default purple to the white text is 4.5. For the focus button, there is a 3.02 contrast between the default purple background and the focus purple background, and 13.62 between focus purple and the white button text, and 12.57 between the focus purple and the page background light yellow." /></p><p><a href="https://buttonbuddy.dev/" rel="noopener noreferrer">Meet ButtonBuddy</a> and learn more about button contrast, as well as generate your own accessible palette. And if you are trying to get by without underlining links within text blocks (which you should really re-consider), use <a href="https://contrast-triangle.com/" rel="noopener noreferrer">Contrast Triangle</a> to compute the three colors needed since a link using only color to distinguish itself must have enough contrast against the surrounding text.</p><div class="heading-wrapper h3">
<h3 id="bonus-color-fix-windows-high-contrast">Bonus color fix: Windows High-Contrast</h3>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#bonus-color-fix-windows-high-contrast" aria-labelledby="bonus-color-fix-windows-high-contrast">
<span hidden="">#</span>
</a></div><p>"Bonus" as in an extra tip, but resolving for this mode very much counts as a baseline requirement for color contrast!</p><p>Some of your users may be modifying their Windows machine to use a "high contrast" theme, which corresponds to the "forced colors" spec for CSS. In this mode, almost all colors are replaced by a reduced palette. This can cause a loss of meaning of icons, cause critical graphics like your logo to be visually hidden, or detrimentally remove boundaries between UI elements.</p><p>Learn more and review techniques for <a href="https://moderncss.dev/modern-css-upgrades-to-improve-accessibility/#respecting-color-and-contrast-settings" rel="noopener noreferrer">handing high-contrast/forced colors mode with CSS</a>.</p><div class="heading-wrapper h2">
<h2 id="keyboard-interaction">Keyboard Interaction</h2>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#keyboard-interaction" aria-labelledby="keyboard-interaction">
<span hidden="">#</span>
</a></div><p>If an interaction relies on a mouse-initiated action, it needs to be keyboard accessible too. This means it may need to respond to Space and/or Enter as a trigger (hint: you get that for free with <code><button></code>).</p><p>Here are some keyboard interactions to evaluate for your feature:</p><ul><li><strong>If it opens something</strong>, it may need to close with Escape. </li><li><strong>If it's scrollable</strong>, it needs to respond to Up/Down arrow keys. </li><li><strong>If it's a group of related options</strong> (like autocomplete or tabs), it may need to respond to Up/Down or Left/Right arrow keys (search phrase: roving tabindex).</li><li><strong>If it opens a dialog/modal</strong>, it needs to prevent tab access with elements outside of that experience (search phrases: "trapping focus" and "inert").</li><li><strong>If it's interactive at all</strong>, it needs to be able to gain keyboard focus, and that focus needs to have a visible style (which is test #3).</li><li><strong>If a sighted mouse user can explore and make independent selections</strong> (like in an autocomplete), a keyboard user needs to be able to as well. This likely means allowing a combination of tab, arrow keys, and Enter to explore and then make a selection.</li><li><strong>If a <code>:hover</code> triggers content,</strong> then so should <code>:focus</code> (ex. menus). You will also need a way to close this content, whether that's a tap/click outside or Escape key, and ensure that the method you choose is also accessible for touchscreen users.</li></ul><p>When you try to create a "pure CSS" solution for interactive experiences, you are quite likely failing to meet these conditions. To ensure the accessibility of your interface, JavaScript is a necessary addition to accomplish focus management, respond to keyboard events, and toggle ARIA attributes. In my article for Smashing, I review <a href="https://www.smashingmagazine.com/2021/06/css-javascript-requirements-accessible-components/" rel="noopener noreferrer">JavaScript requirements for accessible custom controls</a>.</p><div class="heading-wrapper h2">
<h2 id="visible-focus">Visible Focus</h2>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#visible-focus" aria-labelledby="visible-focus">
<span hidden="">#</span>
</a></div><p>Focusable elements require visible focus so that sighted keyboard users can track where focus is on the page. "Visible" means there is a change between the unfocused and focused states - often an outline, sometimes a color change. </p><p>Native focusable elements include:</p><ul><li>form controls: <code>input</code>, <code>select</code>, <code>textarea</code></li><li><code>button</code></li><li><code>a</code></li><li><code>summary</code></li></ul><p>There are rules for defining focus states which fall under <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html" rel="noopener noreferrer">WCAG 2.4.7 - Focus Visible</a> and which is being further clarified in WCAG 2.2 with <a href="https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance-minimum.html" rel="noopener noreferrer">2.4.11 - Focus Appearance (Minimum)</a>, which at present is a draft but approaching a finalized state.</p><p>Frequently, the reason this is removed is due to feeling the native browser style is not attractive or doesn't fit in with the design choices of the app. Over the years, this has led to developers completely removing focus outlines without a fallback style.</p><p>In 2021, evergreen browsers actually switched their default focus behavior to that of the modern CSS pseudo selector <code>:focus-visible,</code> which is designed to only show a default outline based on heuristics. In practical terms, this generally means it will show for focusable controls when keyboard navigation is detected but not mouse click. This functionality removes the weight behind the argument of focus styles being "ugly" since it reduces the scenarios where it is present.</p><p>The test here is to make sure you have either allowed browser default styles or that your custom focus style meets the WCAG criteria. Sara Soueidan has created a <a href="https://www.sarasoueidan.com/blog/focus-indicators/" rel="noopener noreferrer">comprehensive guide to designing accessible, WCAG-compliant focus indicators</a>.</p><p>Review my technique for <a href="https://css-tricks.com/standardizing-focus-styles-with-css-custom-properties/" rel="noopener noreferrer">standardizing focus styles using custom properties</a> to design a consistent yet flexible method to manage focus across your site or application.</p><div class="heading-wrapper h2">
<h2 id="zoom-levels">Zoom Levels</h2>
<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/#zoom-levels" aria-labelledby="zoom-levels">
<span hidden="">#</span>
</a></div><p>You've tested across viewport sizes using browser dev tools as well as on real mobile devices, and you're happy with your site's responsive behavior. But you're probably missing one test point: desktop zoom.</p><p><a href="https://www.w3.org/WAI/WCAG21/Understanding/reflow.html" rel="noopener noreferrer">WCAG 1.4.10 - Reflow</a> provides the condition that your feature should be able to accommodate desktop zoom up to 400%. At this high zoom level, your layout probably kicks into what you may consider your "mobile" layout, but importantly the context of these users is different. Additionally, their orientation aspect ratio is closer to landscape (wider than height), whereas your "mobile" styles probably assume a default portrait (taller than width) orientation.</p><aside role="note"><p>Viewport width is not a proxy for user or device capabilities!</p></aside><p>Some examples of possible issues when your layout doesn't accommodate high zoom:</p><ul><li>sticky navigation that covers half or more of the viewport</li><li>contained scroll areas that assume a mobile portrait aspect ratio become unscrollable/cut-off</li><li>unwanted results when using <a href="https://moderncss.dev/generating-font-size-css-rules-and-creating-a-fluid-type-scale/" rel="noopener noreferrer">fluid typography</a> techniques</li><li>overflow or overlap issues that cut-off content</li><li>margin and padding spacing appearing too large relative to the content size</li></ul><p>This particular criterion has become something I've created a few resources on. Check these out to learn more about what can be affected and modern CSS ways to anticipate, address, and reduce potential issues:</p><ul><li><a href="https://moderncss.dev/modern-css-upgrades-to-improve-accessibility/#desktop-zoom-and-reflow" rel="noopener noreferrer">Desktop Zoom and Reflow</a> - discusses the criteria and section spacing</li><li>More information about <a href="https://moderncss.dev/developing-for-imperfect-future-proofing-css-styles/#wcag-success-criterion-1410-reflow" rel="noopener noreferrer">the impact of high zoom</a> and handling it with thoughtfully applying responsive units</li><li>Contextual spacing techniques that affect small screens and high zoom levels as an <a href="https://moderncss.dev/contextual-spacing-for-intrinsic-web-design/" rel="noopener noreferrer">article</a> and my <a href="https://noti.st/st3ph/YWbRfR/scaling-css-layout-beyond-pixels#video" rel="noopener noreferrer">recorded presentation</a> from beyond tellerrand</li></ul><hr /><p>Begin incorporating these four tests not just at the end, but include their consideration at the beginning of feature development. Share this knowledge with designers, project managers, and even business owners. </p><p>Best of luck on your journey to implementing more accessible features!</p>
In Defense of Sass2022-03-14T00:00:00.000Zhttps://thinkdobecreate.com/articles/in-defense-of-sass/
<p>I've been writing my CSS via Sass for nearly a decade. And, I'll continue to do so even with all the tremendously awesome features making their way into CSS, including nesting.</p><p>Why? Because I have found Sass to be an excellent complement to how I approach writing styles, particularly in a team environment. The ability to organize styles into directories such as for design system components but bring them together into a unified stylesheet is really great. So are the built-in methods to cleanly override variables using the <code>!default</code> flag to prevent cascade conflicts or needing to specifically write extra overriding styles. I'm also used to using <a href="https://stylelint.io/" target="_blank" rel="noopener noreferrer">stylelint</a> within a team to provide extra linting and reinforce style consistency.</p><p>I appreciate being able to set constant variables with Sass while still benefiting from the "client-side" nature of CSS custom properties. And the current roadmap for CSS doesn't include things like loops and custom functions, which I also make use of in Sass projects.</p><div class="heading-wrapper h2">
<h2 id="example-generate-themed-button-classes">Example: Generate Themed Button Classes</h2>
<a href="https://thinkdobecreate.com/articles/in-defense-of-sass/#example-generate-themed-button-classes" aria-labelledby="example-generate-themed-button-classes">
<span hidden="">#</span>
</a></div><p>To help understand where Sass still fits, let's look at creating a simple themeable button set using Sass.</p><p>First, we set up a Sass map to hold our constant color values:</p><pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$colors</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span><br /> <span class="token string">"primary"</span><span class="token punctuation">:</span> <span class="token string">"hsl(260, 95%, 70%)"</span><span class="token punctuation">,</span><br /> <span class="token string">"secondary"</span><span class="token punctuation">:</span> <span class="token string">"hsl(320, 95%, 60%)"</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>For extended flexibility, I also like to create a list to hold the names of my colors:</p><pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$base-colors</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token string">"primary"</span><span class="token punctuation">,</span> <span class="token string">"secondary"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>Then, since these are global values that we will use beyond just our buttons, we'll use a Sass <code>@each</code> loop to output the corresponding CSS custom properties. This uses the <code>$colors</code> map since we need access to both the color name and its value.</p><pre class="language-scss"><code class="language-scss"><span class="token selector">:root </span><span class="token punctuation">{</span><br /> <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$colorName</span>, <span class="token variable">$colorValue</span> in <span class="token variable">$colors</span> </span><span class="token punctuation">{</span><br /> <span class="token property">--<span class="token variable">#{$colorName}</span></span><span class="token punctuation">:</span> <span class="token variable">#{$colorValue}</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre><p>We'll skip the basic styles for buttons (but you can read <a href="https://moderncss.dev/css-button-styling-guide/" target="_blank" rel="noopener noreferrer">my guide to button styling</a> if you're curious), and consider the interesting bit which is creating modifier classes to create the button color variations. This time we use the <code>$base-colors</code> list since we're assigning the custom properties which we reference by the name.</p><pre class="language-scss"><code class="language-scss"><span class="token selector">.button </span><span class="token punctuation">{</span><br /> <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$colorName</span> in <span class="token variable">$base-colors</span> </span><span class="token punctuation">{</span><br /> <span class="token selector"><span class="token parent important">&</span>-<span class="token variable">#{$colorName}</span> </span><span class="token punctuation">{</span><br /> <span class="token property">--button-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--<span class="token variable">#{$colorName}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre><p><strong>The awesome thing about using custom properties within the Sass loop</strong> is that we only have to redefine those cherry-picked values instead of what I did pre-custom properties which was to include a mixin to override rules altogether.</p><p>Now to create new button color variations or change the current ones, we only need to update our Sass <code>$colors</code> map and <code>$base-colors</code> list! And this looping idea can be extended to other instances or used to create more generic color utility classes. </p><p>In a more extensive project I'd create override-able variables for each color value, and likely break out a specific <code>$buttonColors</code> Sass list variable to better control for button-only colors.</p><p>This CodePen demonstrates the full button set created from this technique:</p><p class="codepen" data-default-tab="css,result" data-slug-hash="gOROGoK" data-preview="true" data-user="5t3ph"></p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script><p>You may also enjoy my <a href="https://egghead.io/lessons/scss-access-theme-color-values-with-sass" rel="noopener noreferrer">1 minute egghead video</a> demonstrating an alternate theming technique with Sass.</p><p></p><p></p><p></p>
My Dev Content Creation Journey and Tips for Starting Yours2022-03-07T00:00:00.000Zhttps://thinkdobecreate.com/articles/dev-content-creation-journey/
<p>Once I got serious about developer content creation, it quickly inspired more and more content. Since January 2020, I've written over 100 articles, produced over 60 instructional videos, created <a href="https://learnfromsteph.dev/" target="_blank" rel="noopener noreferrer">a course for beginner webdevs</a>, published <a href="https://www.npmjs.com/~5t3ph" target="_blank" rel="noopener noreferrer">9 packages</a>, <a href="https://buttonbuddy.dev/" target="_blank" rel="noopener noreferrer">1 web app</a>, maintain 3 blogs, and have many Eleventy-related projects. Blogging is what I'm most known for, and I actually was recruited for my current job thanks to <a href="https://moderncss.dev/" target="_blank" rel="noopener noreferrer">ModernCSS.dev</a>. I have not fully monetized any of my projects, but do receive a very small bit of monthly ad revenue as well as modest royalties from egghead. Occasionally, <a href="https://www.buymeacoffee.com/moderncss" target="_blank" rel="noopener noreferrer">folks will buy me a few coffees</a> which are very appreciated!</p><p>My output has not been consistent (and that's ok!). I went through a heavy push in 2020 as I found myself re-invigorated with my new mission to educate about CSS and accessibility and then fell in love with Eleventy, too. 2021 resulted in lower total output, but I've also found myself with different opportunities such as joining live streams, speaking at conferences and meetups, and guesting on podcasts.</p><p>I've said that the main reason I create projects or write articles is so I can copy from them to speed up my future development. And while I didn't directly set out to become an open-source contributor, it's been very fun and rewarding to have folks appreciate and be able to use my projects. Ultimately, what I produce is about me chasing whatever idea is in my head and working on it when I have time (which is usually for a couple of hours after my kids go to bed a few nights a week 😊).</p><p>My initial content creation goal was to create my <a href="https://learnfromsteph.dev/" target="_blank" rel="noopener noreferrer">beginner webdev course</a>. TBH, it's a little embarrassing looking at it now due to the lower production quality of most of the initial videos, and general inexperience as an instructor. But that was part of the point - I used what I had available for "free" (no new purchases) to test out whether that was <strong>the right path for me</strong> to make content. I used QuickTime to record my screen, a very low-quality lavalier mic for voice-over and then edited the videos using iMovie. The quality improved after I became an egghead instructor and had a better mic and learned how to use Screenflow.</p><p>Alongside that course, <a href="https://dev.to/5t3ph" target="_blank" rel="noopener noreferrer">I began publishing via DEV</a>. I chose this route due to the built-in audience and distribution, but also to reduce the upfront effort for starting to publish my course. DEV was a really great place to publish, and it's where I started the ModernCSS series as well. I highly recommend it if you want to test the waters without the pressure of spinning up and maintaining your own separate environment.</p><p>As I learned from my readers, watched the webdev community conversations, and indulged my own interests, other projects grew such as <a href="https://smolcss.dev/" target="_blank" rel="noopener noreferrer">SmolCSS</a> and <a href="https://11ty.rocks/" target="_blank" rel="noopener noreferrer">11ty Rocks</a>. You can find a nearly complete list of my projects and appearances on <a href="https://thinkdobecreate.com/" target="_blank" rel="noopener noreferrer">my portfolio</a>.</p><p>I'm starting to plan for a few new larger projects in 2022, so stay tuned! I share new projects <a href="https://twitter.com/5t3ph" rel="noopener noreferrer">on Twitter</a> and <a href="https://thinkdobecreate.com/articles/dev-content-creation-journey/#newsletter">in my newsletter</a>.</p><div class="heading-wrapper h2">
<h2 id="tips-for-starting-your-content-creation-journey">Tips for Starting Your Content Creation Journey</h2>
<a href="https://thinkdobecreate.com/articles/dev-content-creation-journey/#tips-for-starting-your-content-creation-journey" aria-labelledby="tips-for-starting-your-content-creation-journey">
<span hidden="">#</span>
</a></div><p>OK! Enough about me - let's get to the tips!</p><ol><li><strong>Getting comfortable with pushing publish</strong> is my number one tip. It's the hardest one, and a related mantra is "perfect is the enemy of done". As soon as your article or project checks the essential boxes, get it published! You can always revise later.</li><li><strong>Don't get caught up on whether it's been done before</strong>. Your unique style and voice may help someone finally understand a concept or your tool or project may jive with their process better than what exists and is similar.</li><li><strong>All progress is good progress!</strong> All of the following count: making a todo list, choosing a color scheme and fonts, researching hosting platforms and making a domain name list, finding tutorials to fill a skills gap, creating a repo, building the foundational HTML, etc. Trade 20 mins of (insert other activity) for 20 mins of progress on your idea - it adds up!</li><li><strong>Set yourself up for success</strong>. Only you know how you work best!</li><li><strong>Progress leads to motivation leads to progress. </strong>Publishing an article and getting your first comment or RT from someone you admire on Twitter or a mention in a newsletter is all rewarding and motivating. Plus - you never know who may see it and how it might lead to an amazing opportunity!</li></ol><p><strong>No ideas?</strong> Make a thing:</p><ul><li>you need to help you right now</li><li>you wish existed in the world</li><li>that fills a need you have unique knowledge about</li><li>that will help you learn something new</li></ul><p><strong>Tips for starting and keeping motivated</strong>:</p><ul><li>Create template repos of your starting points, dotfiles, or whatever else will help you iterate quickly using your tools of choice</li><li>Give yourself a deadline, make a prioritized todo list, and push publish</li><li>Rally some friends to keep you accountable</li><li>Use a hosting platform that lets you create random domains to share for feedback</li><li>Your first thing doesn’t have to be a big splashy project, you can leverage tools like CodePen's real-time editor to make an “app”</li><li>Write just one single blog post and post to a friendly platform like <a href="http://dev.to/" target="_blank" rel="noopener noreferrer">dev.to</a></li><li>Pitch an article to places like <a href="https://css-tricks.com/guest-posting/" target="_blank" rel="noopener noreferrer">CSS-Tricks</a> and <a href="https://www.smashingmagazine.com/write-for-us/" target="_blank" rel="noopener noreferrer">Smashing Magazine</a> and get the benefit of working with an experienced editor and get paid if accepted!</li></ul><p>You may find you also like to do things live to "learn in public" such as starting up a Twitch or YouTube stream. At first, it can seem scary, but the encouragement and extended community I've found <a href="https://twitch.tv/5t3phDev" rel="noopener noreferrer">through streaming</a> has been amazing. I recommend trying it out! It's also great practice if you do want to become a conference speaker or provide other types of live or recorded instruction.</p><p>I hope these tips help, and I can't wait to see what you make and publish!</p>
CSS Quick Tip: Animating in a newly added element2022-02-21T00:00:00.000Zhttps://thinkdobecreate.com/articles/css-animating-newly-added-element/
<p>I've solved the challenge of adding animation to a newly added DOM element several times by way of <code>setTimeout</code> to juggle classes that were tied to CSS transitions. Recently, a friend brought up that they were working on something similar, and it occurred to me that a switch to keyframes just might remove the need for JavaScript.</p><p>So, I whipped up a quick CodePen to vet the idea and sure enough, it worked! </p><p>This technique works because the animation begins playing when the element is added, removing the need to have to add a class to trigger a regular transition. The magic line is:</p><pre class="language-css"><code class="language-css"><span class="token property">animation</span><span class="token punctuation">:</span> show 600ms 100ms <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>0.38<span class="token punctuation">,</span> 0.97<span class="token punctuation">,</span> 0.56<span class="token punctuation">,</span> 0.76<span class="token punctuation">)</span> forwards<span class="token punctuation">;</span></code></pre><p>In this definition, <code>show</code> is the name of the keyframes animation. The first number of <code>600ms</code> is the animation duration (how long it takes to play), and the second number of <code>100ms</code> creates a small delay before the animation begins. </p><p>Then, instead of using a simple easing type such as ease-in, we're using <a href="https://cubic-bezier.com/#.38,.97,.56,.76" target="_blank" rel="noopener noreferrer">a custom cubic-bezier function</a> which in conjunction with the transition causes the final effect to feel like the element is gently expanding into place. </p><p>The last critical part is setting the <code>animation-fill-mode</code> to <code>forwards</code> so that the animation stops on the last frame, aka the <code>100%</code> state. Without that, the element wouldn't stay visible.</p><p>A neat thing about CSS animations is that you don't need to define a starting state for a two-step animation. For this one, we define the starting state as the default style, and then only define the end state - so just 100% - within the keyframes.</p><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> show</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre><p>Here's the CodePen with the effect altogether. The only JS in the pen is to allow you to add a new list item to simulate having items added in a "real" app.</p><p class="codepen" data-default-tab="css,result" data-slug-hash="oNWpYre" data-preview="true" data-user="5t3ph"></p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
Minimum Static Site Setup with Sass2022-02-19T00:00:00.000Zhttps://thinkdobecreate.com/articles/minimum-static-site-sass-setup/
<p>What are you using to build sites these days? For myself, all of my personal projects now use the static site generator Eleventy (check out my resources for that on <a href="https://11ty.rocks/" target="_blank" rel="noopener noreferrer">11ty.Rocks</a>). </p><p>But before that, I briefly used Gulp due to being in a team environment and dealing with cross-environment concerns. It was also a pre-build step before manually copying files into the custom WordPress theme directory. Let's just say it took me several years to understand the purpose of task runners/build tools!</p><p>Before I found Eleventy (aka 11ty), I worked out a command line combination for building a static site that included processing Sass and running the final files through autoprefixer and cssnano.</p><div class="heading-wrapper h2">
<h2 id="build-setup">Build Setup</h2>
<a href="https://thinkdobecreate.com/articles/minimum-static-site-sass-setup/#build-setup" aria-labelledby="build-setup">
<span hidden="">#</span>
</a></div><p>If you don't need any templating languages and just need to get a simple site built plus Sass, <strong>use this as the contents of a fresh package.json</strong>:</p><pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br /> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"project"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"version"</span><span class="token operator">:</span> <span class="token string">"0.1.0"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"description"</span><span class="token operator">:</span> <span class="token string">"SASS compile|autoprefix|minimize and live-reload dev server using Browsersync for static HTML"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"main"</span><span class="token operator">:</span> <span class="token string">"public/index.html"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"author"</span><span class="token operator">:</span> <span class="token string">"5t3ph"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">"build:sass"</span><span class="token operator">:</span> <span class="token string">"sass --no-source-map src/sass:public/css"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"copy:html"</span><span class="token operator">:</span> <span class="token string">"copyfiles -u 1 ./src/*.html public"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"copy"</span><span class="token operator">:</span> <span class="token string">"npm-run-all --parallel copy:*"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"watch:html"</span><span class="token operator">:</span> <span class="token string">"onchange 'src/*.html' -- npm run copy:html"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"watch:sass"</span><span class="token operator">:</span> <span class="token string">"sass --no-source-map --watch src/sass:public/css"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"watch"</span><span class="token operator">:</span> <span class="token string">"npm-run-all --parallel watch:*"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"serve"</span><span class="token operator">:</span> <span class="token string">"browser-sync start --server public --files public"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"start"</span><span class="token operator">:</span> <span class="token string">"npm-run-all copy --parallel watch serve"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"build"</span><span class="token operator">:</span> <span class="token string">"npm-run-all copy:html build:*"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"postbuild"</span><span class="token operator">:</span> <span class="token string">"postcss public/css/*.css -u autoprefixer cssnano -r --no-map"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">"autoprefixer"</span><span class="token operator">:</span> <span class="token string">"^10.4.2"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"browser-sync"</span><span class="token operator">:</span> <span class="token string">"^2.27.7"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"copyfiles"</span><span class="token operator">:</span> <span class="token string">"^2.4.1"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"cssnano"</span><span class="token operator">:</span> <span class="token string">"^5.0.17"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"npm-run-all"</span><span class="token operator">:</span> <span class="token string">"^4.1.5"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"onchange"</span><span class="token operator">:</span> <span class="token string">"^7.1.0"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"postcss-cli"</span><span class="token operator">:</span> <span class="token string">"^9.1.0"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"sass"</span><span class="token operator">:</span> <span class="token string">"^1.49.8"</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre><p>This does not include support for moving assets like images, but you could duplicate the <code>copy:html</code> and <code>watch:html</code> scripts as a basis to include other assets.</p><p><strong>Note</strong>: at the time of publishing, <a href="https://github.com/BrowserSync/browser-sync/issues/1926" rel="noopener noreferrer">browser-sync had an unresolved issue</a> with an old dependency, but since you will not deploy browser-sync as a production dependency, it is low impact.</p><div class="heading-wrapper h3">
<h3 id="project-structure">Project Structure</h3>
<a href="https://thinkdobecreate.com/articles/minimum-static-site-sass-setup/#project-structure" aria-labelledby="project-structure">
<span hidden="">#</span>
</a></div><pre class="language-txt"><code class="language-txt">src/<br />- sass/<br />- - style.scss<br />- index.html</code></pre><div class="heading-wrapper h3">
<h3 id="project-scripts">Project Scripts</h3>
<a href="https://thinkdobecreate.com/articles/minimum-static-site-sass-setup/#project-scripts" aria-labelledby="project-scripts">
<span hidden="">#</span>
</a></div><ol><li><code>npm start</code> - copies <code>src</code> files to <code>public</code> and starts Browsersync server at <code>localhost:3000</code></li><li><code>npm run build</code> - copies files to <code>public</code> and autoprefixes/minifies css</li></ol><hr /><p>If you do need templating or want to write your content in Markdown as well as use Sass, then you might enjoy my Eleventy starter - <a href="https://github.com/5t3ph/11ty-sass-skeleton" target="_blank" rel="noopener noreferrer">11ty Sass Skeleton starter</a>.</p>