CSS and design systems people - BlogFlock 2025-09-18T14:50:30.614Z BlogFlock Michelle Barker, Sara Joy, Robin Rendle, Adam Argyle, Stephanie Eckles, Hidde de Vries, Sara Soueidan, Robin Rendle Joining Shopify - Adam Argyle https://nerdy.dev/joining-shopify?utm_source=rss 2025-09-15T17:00:00.000Z <p>I&#39;m stoked to share my next role:</p> <p><strong>Design Engineer</strong> at <a href="https://www.shopify.com/editions/summer2025">Shopify</a>;<br>alongside <a href="https://x.com/_developit">Jason Miller</a> to hack on next-gen admin UI/UX and a new <a href="https://polaris-react.shopify.com">Polaris</a>.</p> <p>I&#39;m also workin to rejoin the <a href="https://www.w3.org/groups/wg/css/">CSSWG</a> via Shopify too 🙂</p> <p><small>Thanks for all y&#39;all&#39;s support! đŸ’€đŸ€˜đŸ»</small></p> Twitter Integrated Again - Adam Argyle https://nerdy.dev/twitter-integrated-again?utm_source=rss 2025-09-13T17:10:45.000Z <p>Twitter comments, likes and reposts are now integrated.</p> Ditch those words! - Robin Rendle https://robinrendle.com/notes/ditch-those-words/ 2025-09-13T16:18:00.000Z <p>Over the past couple of years I’ve noticed that 90% of my design feedback comes down to these three things:</p> <ol> <li>Ditch those words!</li> <li>Ditch those words!</li> <li>Ditch those words!</li> </ol> <p>It’s the fastest way to make a design more easily understood because almost every interface tries to explain too much at the wrong time and is far too yappy. Modern interface design is made up of sentences and sentences of needless information, over-explaining every detail and presenting too many ideas and concepts at the wrong time.</p> <p>It’s strange because as an annoying book person I believe in words! I want more and more words. I want fancy words and long-winded words and difficult words. I demand complexity! I want to think and ponder and struggle with a sentence that is trying to drag me along with it on a rip-roaring ride that I can barely comprehend. This, to me, is the textbook definition of fun.</p> <p>But here’s what modern UI design looks like: There’s always a confusing title; it doesn’t quickly tell me what to do or what it wants me to understand; beneath that there’s a subtitle, explaining the title again; beneath that there’s several sentences that restates the title and subtitle but simply jumbles all the words around to make it justify its existence; then the button—there is always a button—and it asks me to “Confirm” or “Apply” but as to what I’m confirming or applying I have absolutely no idea unless I go back to the text and fight my way through it all again.</p> <p>Folks will spend so much time adding fancy illustrations and making sure the icons aren’t blurry but when it comes to words and actions in interfaces they seem to gloss right over them. We have learned to scan UIs like robots because the folks who designed them don’t care for the words as much as they cared for the fonts or the colors.</p> <p>But words in an interface have a different job than they do in a book and behave in a different way. Every word in a UI needs to act like a hammer, with each successive word the interface should become clearer, more easily understood. If you put a word like <code>Explore</code> in an interface it might make sense but now add another navigation item like <code>Discover</code> beneath it and now both words make no sense. The UI has collapsed into meaninglessness and folks are forced to click and think and furrow their brows to understand the difference between the two. This is because words in interfaces have relationships: they all work together to build comprehension. If one button or title or navigation item is confusing then it makes everything else more confusing, too.</p> <p>The cynic in me worries that the folks who made this interface don’t want me to read the popup or modal or alert or web page or list of settings or whatever and they really just want me to click a button. The words are <em>designed</em> to be longwinded and confusing. They just want the click. The more hopeful designer in me worries that these folks just didn’t spend the time necessary to understand what they want from me. Either way, it sucks.</p> <p>So this is feedback I give to myself as I’m working on an interface today: Remove that subtitle! Make that title as brief as possible! Kill that second sentence! Make it impossible for users <em>not</em> to read this! Disambiguate! Separate these concepts! Hide the fluff! Say one thing! Ditch those words!</p> WWW Ep209 - Adam Argyle https://nerdy.dev/www-ep209?utm_source=rss 2025-09-11T15:42:49.000Z <p><span class="Tag">Ep #209</span><br> <strong>Is Cracker Barrel a JS Framework?</strong></p> <p><a href="https://robbiethewagner.dev">Robbie</a> and I talk about JavaScript trends, from the overuse of hooks to frameworks chasing sameness, and why <a href="https://www.crackerbarrel.com/allthemore">Cracker Barrel’s rebrand</a> feels like a frontend metaphor.</p> <p>‷ <a href="https://whiskey.fm/is-cracker-barrel-a-js-framework">whiskey.fm</a> · <a href="https://www.youtube.com/watch?v=IxQpEZmVb1Q">youtube</a> · <a href="https://open.spotify.com/show/19jiuHAqzeKnkleQUpZxDf">spotify</a> · <a href="https://podcasts.apple.com/us/podcast/is-cracker-barrel-a-js-framework/id1552776603?i=1000726091007">apple</a></p> One List To Rule Them All - Adam Argyle https://nerdy.dev/cascading-secret-sauce?utm_source=rss 2025-09-10T23:02:20.000Z <img style="display: none" src="https://nerdy.dev/media/feature-list-hero.jpg" alt="100+ CSS features from the past 5 years or so" height="371" width="1024" /> <p>Whether I&#39;m giving a talk or on a podcast, these two things constantly pop up:</p> <ul> <li>how do I find what to study to keep up?</li> <li>what&#39;s new in CSS?</li> </ul> <p>If you&#39;ve wondered those things before, <strong>then this list is for you.</strong></p> <p>Find something you&#39;ve never heard of, click the link; and look at you, you&#39;re already getting more familiar with what&#39;s new!</p> <h2> Selectors <a name="selectors" href="#selectors">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:has">:has()</a></li> <li><a href="https://web.dev/articles/css-is-and-where">:is() and :where()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible">:focus-visible</a></li> <li><a href="https://web.dev/articles/user-valid-and-user-invalid-pseudo-classes">:user-valid</a></li> <li><a href="https://web.dev/articles/user-valid-and-user-invalid-pseudo-classes">:user-invalid</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:active-view-transition">:active-view-transition</a></li> <li><a href="https://www.w3.org/TR/css-view-transitions-2/#the-active-view-transition-type-pseudo">:active-view-transition-type()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:target-current">:target-current</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:popover-open">:popover-open</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:scope">:scope</a></li> </ul> <h2> Pseudo Elements <a name="pseudo-elements" href="#pseudo-elements">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop">::backdrop</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-new">::view-transition-new()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-old">::view-transition-old()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-group">::view-transition-group()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-image-pair">::view-transition-image-pair()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::scroll-button">::scroll-button()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::scroll-marker">::scroll-marker()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::details-content">::details-content</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::picker">::picker()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::picker-icon">::picker-icon</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::checkmark">::checkmark</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::column">::column</a></li> </ul> <h2> Language <a name="language" href="#language">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Nesting_selector">CSS Nesting</a></li> </ul> <h2> @rules <a name="@rules" href="#@rules">#</a> </h2> <ul> <li><a href="https://web.dev/articles/at-property">@property</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@container">@container</a><ul> <li><a href="https://web.dev/articles/css-container-queries">size query</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/style-queries">style query</a></li> <li><a href="https://developer.chrome.com/blog/css-scroll-state-queries">state query</a></li> </ul> </li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@scope">@scope</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@layer">@layer</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/scroll-driven-animations#:~:text=create%20one%20set%20of%20keyframes%20that%20already%20contains%20the%20range%20information">@keyframes with entry and exit</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@supports">@supports</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style">@starting-style</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@view-transition">@view-transition</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@position-try">@position-try</a></li> <li><a href="https://css.oddbird.net/sasslike/mixins-functions/">@mixin</a></li> <li><a href="https://css.oddbird.net/sasslike/mixins-functions/">@function</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/if">@if</a></li> </ul> <h2> Color <a name="color" href="#color">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix">color-mix()</a></li> <li><a href="https://developer.chrome.com/blog/css-relative-color-syntax">color(from 
)</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/contrast-color">contrast-color()</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide">oklch(), oklab(), hwb(), color()</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide">linear-gradient(in oklab, 
)</a></li> </ul> <h2> Functions <a name="functions" href="#functions">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/var">var()</a></li> <li><a href="https://linear-easing-generator.netlify.app/">linear()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content">fit-content()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/repeat">repeat()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/min">min()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/max">max()</a></li> <li><a href="https://developer.chrome.com/blog/advanced-attr">attr()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/env">env()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path">circle(), polygon()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline/scroll">scroll()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline/view">view()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/clamp">clamp()</a></li> <li><a href="https://css-tricks.com/almanac/functions/s/sibling-count/">sibling-count() and sibling-index()</a></li> <li><a href="https://web.dev/articles/css-trig-functions">cos(), sin(), tan(), pow(), atan2() asin() acos()</a></li> <li><a href="https://css-tricks.com/css-shape-commands/">shape()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark">light-dark()</a></li> <li><a href="https://www.bram.us/2022/01/20/detect-at-rule-support-with-the-at-rule-function/">at-rule()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/image-set">image-set()</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/anchor">anchor()</a></li> <li><a href="https://css-tricks.com/almanac/functions/r/random/">random()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#random-item">random-item()</a></li> <li><a href="https://www.w3.org/TR/css-forms-1/#control-value">control-value()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#progress-func">progress()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#media-progress-func">media-progress()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#container-progress-func">container-progress()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#mix">mix()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#calc-mix">calc-mix()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#cross-fade">cross-fade()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#transform-mix">transform-mix()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#first-valid">first-valid()</a></li> <li><a href="https://www.w3.org/TR/css-values-5/#toggle-notation">toggle()</a></li> </ul> <h2> Properties <a name="properties" href="#properties">#</a> </h2> <ul> <li><a href="https://web.dev/articles/accent-color">accent-color</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme">color-scheme</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/container-type">container-type</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility">content-visibility</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/contain-intrinsic-size">contain-intrinsic-size</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio">aspect-ratio</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition">animation-composition</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline">animation-timeline</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-range">animation-range</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/css-text-wrap-balance">text-wrap</a></li> <li><a href="https://css-tricks.com/colrv1-and-css-font-palette-web-typography/">font-palette and font-palette-values</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-gutter">scrollbar-gutter</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/forced-color-adjust">forced-color-adjust</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/reading-flow">reading-flow</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior">scroll-behavior</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/animate-to-height-auto">interpolate-size</a></li> <li><a href="https://frontendmasters.com/blog/understanding-css-corner-shape-and-the-power-of-the-superellipse/">corner-shape</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior">overscroll-behavior</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-marker-group">scroll-marker-group</a></li> <li><a href="https://drafts.csswg.org/css-overflow-5/#scroll-target-group">scroll-target-group</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior">transition-behavior</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color">scrollbar-color and scrollbar-size</a></li> <li><a href="https://developer.chrome.com/blog/css-text-box-trim">text-box</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/anchor-name">anchor-name</a></li> <li><a href="https://css-tricks.com/almanac/properties/a/anchor-scope/">anchor-scope</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position-anchor">position-anchor</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position-area">position-area</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position-try-fallbacks">position-try-fallbacks</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position-try-order">position-try-order</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position-visibility">position-visibility</a></li> <li><a href="https://developer.chrome.com/docs/css-ui/css-field-sizing">field-sizing</a></li> </ul> <h2> Values <a name="values" href="#values">#</a> </h2> <ul> <li>grid-template-columns: <a href="https://web.dev/articles/css-subgrid">subgrid</a>;</li> <li>text-align: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-align">start | end</a>;</li> <li>overflow: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overflow">clip</a>;</li> </ul> <h2> Queries: <a name="queries:" href="#queries:">#</a> </h2> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast">@media (prefers-contrast)</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-data">@media (prefers-reduced-data)</a></li> </ul> <h2> Units <a name="units" href="#units">#</a> </h2> <p>There&#39;s a <a href="/new-relative-units-ric-rex-rlh-and-rch">whole lot of units</a> now. In my opinion, each are unique and useful in their own occasions. Super powers, knowing which to use when.</p> <h3> Relative <a name="relative" href="#relative">#</a> </h3> <ul> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">ex</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">ch</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">cap</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">ic</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">lh</a></li> </ul> <h3> Root Relative <a name="root-relative" href="#root-relative">#</a> </h3> <ul> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">rex</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">rch</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">rlh</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">ric</a></li> <li><a href="https://www.w3.org/TR/css-values-4/#font-relative-lengths">rcap</a></li> </ul> <h3> Absolute <a name="absolute" href="#absolute">#</a> </h3> <ul> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">pt</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">pc</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">in</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">cm</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">mm</a></li> <li><a href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#:~:text=things%20will%20become.-,ABSOLUTE%20LENGTH%20UNITS,-The%20following%20are">Q</a></li> </ul> <h3> Viewport <a name="viewport" href="#viewport">#</a> </h3> <ul> <li><a href="https://web.dev/blog/viewport-units">vw</a></li> <li><a href="https://web.dev/blog/viewport-units">vh</a></li> <li><a href="https://web.dev/blog/viewport-units">vi</a></li> <li><a href="https://web.dev/blog/viewport-units">vb</a></li> <li><a href="https://web.dev/blog/viewport-units">vmin</a></li> <li><a href="https://web.dev/blog/viewport-units">vmax</a></li> <li><a href="https://web.dev/blog/viewport-units">dvw</a></li> <li><a href="https://web.dev/blog/viewport-units">dvh</a></li> <li><a href="https://web.dev/blog/viewport-units">dvi</a></li> <li><a href="https://web.dev/blog/viewport-units">dvb</a></li> <li><a href="https://web.dev/blog/viewport-units">dvmin</a></li> <li><a href="https://web.dev/blog/viewport-units">dvmax</a></li> <li><a href="https://web.dev/blog/viewport-units">svw</a></li> <li><a href="https://web.dev/blog/viewport-units">svh</a></li> <li><a href="https://web.dev/blog/viewport-units">svi</a></li> <li><a href="https://web.dev/blog/viewport-units">svb</a></li> <li><a href="https://web.dev/blog/viewport-units">svmin</a></li> <li><a href="https://web.dev/blog/viewport-units">svmax</a></li> <li><a href="https://web.dev/blog/viewport-units">lvw</a></li> <li><a href="https://web.dev/blog/viewport-units">lvh</a></li> <li><a href="https://web.dev/blog/viewport-units">lvi</a></li> <li><a href="https://web.dev/blog/viewport-units">lvb</a></li> <li><a href="https://web.dev/blog/viewport-units">lvmin</a></li> <li><a href="https://web.dev/blog/viewport-units">lvmax</a></li> </ul> <h3> Container <a name="container" href="#container">#</a> </h3> <ul> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqw</a></li> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqh</a></li> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqi</a></li> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqb</a></li> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqmin</a></li> <li><a href="https://css-tricks.com/container-query-units-cqi-and-cqb/">cqmax</a></li> </ul> <p>Have a suggestion? Let me know on <a href="https://bsky.app/profile/nerdy.dev">Bluesky</a> or <a href="https://twitter.com/argyleink">Twitter</a>! đŸ€</p> Poverty, By America - Robin Rendle https://robinrendle.com/notes/notes-on-poverty/ 2025-09-07T16:03:15.000Z <p>There are books and then there are <em>books</em>. The kind where you can’t put down until they’re finished with you. The kind that captures every atom of your attention and changes something deep down. You walk away altered, the words having not really been words or sentences but something else altogether.</p> <p>That’s how I felt reading Matthew Desmond’s <a href="https://bookshop.org/p/books/poverty-by-america-matthew-desmond/c06303975ef111ba"><em>Poverty, By America</em></a>. This is no dreamy communist manifesto, no incoherent rant that leads to nothing but sadness and frustration, but a shocking book full of actionable, kind ideas entirely backed by careful study of a complex problem. Desmond makes his argument clear through this complexity though: the reason why poor folks are poor is because rich folks are rich.</p> <p>Here’s my notes.</p> <hr /> <blockquote> <p>Poverty isn't simply the condition of not having enough money. It's the condition of not having enough choice and being taken advantage of because of that.</p> </blockquote> <p>(I remember being caught in a web of overdraft fees when I struggled with money. There’s still this lingering feeling fifteen years later where I doubt every time a check will clear, a credit card will go through. I still assume that banks have caught me in some great trap beyond my comprehension. There’s a spider lurking behind me, ready and waiting to devour every paycheck that clears my account. This is not a healthy way to run a society, or a healthy way to live. But tens of millions of Americans do.)</p> <hr /> <blockquote> <p>When we are preoccupied by poverty, “we have less mind to give to the rest of life.” Poverty does not just deprive people of security and comfort; it siphons off their brainpower, too.</p> </blockquote> <p>(I remember being shocked by how similar poverty felt like a sickness, as if I had blinkers on, as if a strong vignette had been applied to my vision. Money was all I could think about. I would count the pounds and pennies, counting and counting and counting at night. I couldn’t think straight, I couldn’t think about a 401k or future investments because I was so paralyzed by Today, this big and brutal and terrifying thing. What if someone after work asked me out for a beer? What if we walk passed a shop and my credit card fails when trying to buy water? What if someone finds out how much is in my account?)</p> <p>(And yet! I was one of the lucky ones to have family to bail me out, as embarrassing as it was to ask them over and over again. Most folks however don’t have people to help them. This is what the government should be. And, currently, what it is not.)</p> <p>(But we can fix this.)</p> <hr /> <blockquote> <p>A higher minimum wage is an antidepressant. It is a sleep aid. A stress reliever. Vocal segments of the American public, those with brain space to spare, seem to believe the poor should change their behavior to escape poverty. Get a better job. Stop having children. Make smarter financial decisions. In truth, it’s the other way around: Economic security leads to better choices.</p> </blockquote> <p>(I remember my first real paycheck. The one where I didn’t have to struggle. The one where I was lifted out of worrying so much. I could suddenly go out and buy food and start going out for dinner or the pub intermittently without feeling anxious the whole time about embarrassing myself by my card failing. I could make rent. But it wasn’t all these material things that money gifted me: it was sleep. With the sudden turn of a week I could now make predictions about my future. Mere days before my life was broken up into excruciatingly long weeks. Paycheck, no-paycheck, no-paycheck, no-paycheck. This is not a healthy way to run a society, etc. etc.)</p> <hr /> <blockquote> <p>Somehow, the United States has the unique distinction of lacking universal healthcare while still having the most expensive healthcare system in the world.</p> </blockquote> <p>(One time back in the UK I had 40 quid in my bank account but found myself with a serious and embarrassing medical emergency. At midnight I went to the hospital and I suddenly found myself begging a doctor for help in a corridor outside his office. He told me the STD clinic opens in the morning, come back then. In agony I laughed and said “I might not be a doctor my dude but I can GUARANTEE that isn’t the problem here.” A few days later, the embarrassing surgery is over, they tell me to go, and I simply walk out of the hospital. There’s no pay station, no worry about handing out cash or finding myself slammed with debt because the UK has a modern, humane health care system. When I moved to the states I learned that how much money I make doesn’t really matter. One foul move, an uncontrollable accident like the one I had back in the UK, and that’s all it takes to lose your financial footing. And, because of this, poverty haunts everyone in America.)</p> <p>(But we can fix this.)</p> <p>(I think this is why I loved this book. It’s angry but not cynical. Desmond argues over and over again that we have fixed the balance of power in this country before and we can do it again. Poverty is not a hex, a curse,a chronic condition or necessary evil. It can be fixed!)</p> <p>(We just have to make it so.)</p> Gradient Style Is Out Of Beta - Adam Argyle https://nerdy.dev/gradient.style-is-out-of-beta?utm_source=rss 2025-08-28T20:39:59.000Z <img style="display: none" src="https://nerdy.dev/media/gradient-layered-1.jpg" alt="some title" height="956" width="1756" /> <p>I&#39;m happy to share that <a href="https://gradient.style">gradient.style</a> is out of beta and:</p> <ul> <li>has been <a href="https://github.com/argyleink/gradient-style">Open Sourced</a></li> <li>finally supports multiple background layers</li> </ul> <p>Open to feedback and comments 🙂</p> The Making of gradient.style - Adam Argyle https://nerdy.dev/the-making-of-gradient.style?utm_source=rss 2025-08-27T05:45:03.000Z <img style="display: none" src="https://nerdy.dev/media/gradient-peek-thumb.jpg" alt="A photo of sketch notes that shows split color stop design" height="950" width="1782" /> <p>Found these pics in a drawer and thought it&#39;d be fun to share the journey of creating a <a href="https://www.w3.org/TR/css-images-3/">CSS spec</a> compliant gradient generator <a href="/a-next-gen-css-gradient-builder">in 2023</a>.</p> <p><q class="info"><a href="https://gradient.style">gradient.style</a><br>A CSS5 HDR color enabling gradient tool</q></p> <p>Can even <a href="http://localhost:3030/gradient-stripes-with-hard-stops-visualized">visualize effects using shorthands</a> and DX tricks.</p> <h2> Gradients and Their Lines <a name="gradients-and-their-lines" href="#gradients-and-their-lines">#</a> </h2> <p>Here&#39;s a sketch of a linear gradient line. The top left image shows a triple color stop gradient, where the 2nd gradient stop uses the double position syntax to spread over more of the line than the other colors. </p> <p><picture> <source srcset="/media/linear-gradient.avif" type="image/avif"> <source srcset="/media/linear-gradient.webp" type="image/webp"> <img loading="lazy" src="/media/linear-gradient.jpg" alt="" title="A paper sketch showing various UI elements for a linear gradient control. The main element is a horizontal slider with color stops at 25%, 50%, and 80%, labeled with hex codes. Other sketches include a vertical version of the slider, a close-up of a circular control with percentage labels, and a diagram of a slider track with a movable handle. " decoding="async" width="1920" height="1440" /> </picture></p> <p>I&#39;ll be calling the colors in a gradient a color stop đŸ€“</p> <p>There&#39;s also a depiction of <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient#color-hint">transition hints</a> and an inline color adjuster concept. I hadn&#39;t quite figured out how the color picker would work yet.</p> <p>This next concept shows the sketched linear gradient line concept being tested with angles and various syntax. </p> <p><picture> <source srcset="/media/linear-gradient-test.avif" type="image/avif"> <source srcset="/media/linear-gradient-test.webp" type="image/webp"> <img loading="lazy" src="/media/linear-gradient-test.jpg" alt="" title="Sketches of linear gradients at different angles, including horizontal, vertical, and diagonal lines. The diagrams show a line with color stops inside a rectangular bounding box. One sketch includes a 90-degree gradient with labels for Red 25% and Blue. Other sketches demonstrate diagonal gradients at various angles, including a central cross shape and a spinner for rotating the gradient angle. " decoding="async" width="1920" height="1440" /> </picture></p> <p>Putting the concept to the test essentially! Testing how transition hints and double stop positions might work in practice.</p> <p>Coding was the only way to fully test the solution, but still fun to see how far I could get on paper.</p> <p>Here&#39;s some conic and radial gradient line concepts.</p> <p><picture> <source srcset="/media/gradient-draft.avif" type="image/avif"> <source srcset="/media/gradient-draft.webp" type="image/webp"> <img loading="lazy" src="/media/gradient-draft.jpg" alt="" title="A series of sketches showing different ways to control a conic gradient. Diagrams illustrate a circle with a central point and a movable handle to define the angle and size of the gradient. Other sketches show how these controls would look within a UI panel, including a circular control with a handle and a more complex interface with sliders for Angle and Size. " decoding="async" width="1920" height="1440" /> </picture></p> <h2> Stops &amp; Hints <a name="stops-&amp;-hints" href="#stops-&amp;-hints">#</a> </h2> <p>Here are some concepts and depictions of the colors (or stops as I&#39;ll start referring to them as) on a gradient line. </p> <p>Some more concepts of a color picker overlay too.</p> <p><picture> <source srcset="/media/color-picker.avif" type="image/avif"> <source srcset="/media/color-picker.webp" type="image/webp"> <img loading="lazy" src="/media/color-picker.jpg" alt="" title="UI sketches for color and gradient controls. The page features multiple vertical and horizontal layouts for sliders with numbered color stops and text input fields for color codes. A central sketch shows a circular color picker with a slider and a label for COLOR with a value of &#39;25% .5 100&#39;. Other elements include a menu and a simplified view of a color stop with its associated color and percentage value. " decoding="async" width="1920" height="1440" /> </picture></p> <p>Stops can have 2 positions on the line, a start and end. Most people don&#39;t know this! I chose to visualize it by splitting the cirle into halves, each half representing a stop position.</p> <p><picture> <source srcset="/media/stops-list.avif" type="image/avif"> <source srcset="/media/stops-list.webp" type="image/webp"> <img loading="lazy" src="/media/stops-list.jpg" alt="" title="UI component sketches, primarily focusing on a vertical list of color controls. The main sketch shows a list with two numbered items, each containing a color swatch, a text field for a hex code, and a horizontal slider. Other sketches show variations of these controls, including one with a single slider and percentage value. A small box lists actions like &#39;Copy Color,&#39; &#39;Duplicate,&#39; &#39;Move Up,&#39; &#39;Move Down,&#39; and &#39;Delete.&#39; A bottom sketch shows a circular handle on a horizontal slider. " decoding="async" width="1920" height="1440" /> </picture></p> <p>Any 2 stops also have a transition hint between them, which is a value that indicates how the stop should transition to the next stop. </p> <p><picture> <source srcset="/media/split-stops.avif" type="image/avif"> <source srcset="/media/split-stops.webp" type="image/webp"> <img loading="lazy" src="/media/split-stops.jpg" alt="" title="A sketch focusing on linear and radial gradient UI controls. The top half shows horizontal linear gradient sliders with different arrangements of color stops and labels like &#39;25%&#39;, &#39;40%&#39;, &#39;60%&#39;, and &#39;80%&#39;. The bottom half details radial gradient controls, including a circle with color stops and a handle to define the size and position. Notes describe the elements as &#39;Color Stop,&#39; &#39;Color Positions,&#39; &#39;Start,&#39; and &#39;End.&#39; " decoding="async" width="1920" height="1440" /> </picture></p> <p>Here&#39;s more sketches of colors and hints. I have no idea what that math calculation means anymore.</p> <p><picture> <source srcset="/media/transition-hints.avif" type="image/avif"> <source srcset="/media/transition-hints.webp" type="image/webp"> <img loading="lazy" src="/media/transition-hints.jpg" alt="" title="A sketch page with diagrams explaining linear gradient transitions and controls. One large drawing shows a linear gradient with a line passing through a rectangular container and two color stops. Smaller sketches show a close-up of a color stop with a handle for moving its position and a &#39;Transition Hint&#39; element for adjusting the gradient&#39;s softness. A separate circular diagram shows color stops on a radial path. " decoding="async" width="1920" height="1440" /> </picture></p> <p>These are more sketches testing out various gradients and their estimated visualizations.</p> <p><picture> <source srcset="/media/stops-overlay.avif" type="image/avif"> <source srcset="/media/stops-overlay.webp" type="image/webp"> <img loading="lazy" src="/media/stops-overlay.jpg" alt="" title="A page of pencil sketches illustrating different gradient controls and behaviors. Diagrams show a square with a central point and color stops on the corners or a circular path. There are also sketches of lines connecting different points, labeled &#39;STOP,&#39; &#39;Pos X,&#39; &#39;Pos Y,&#39; and &#39;SIZE.&#39; One sketch depicts a control with a spinner and a central point to define the angle of a gradient. " decoding="async" width="1920" height="1440" /> </picture></p> <h2> GUI Explorations <a name="gui-explorations" href="#gui-explorations">#</a> </h2> <p>The UI needs to show a layers list view (which I still plan to enable more layers!), a gradient canvas preview, a color stops list view and the CSS output for copying.</p> <p><picture> <source srcset="/media/gui-explorations.avif" type="image/avif"> <source srcset="/media/gui-explorations.webp" type="image/webp"> <img loading="lazy" src="/media/gui-explorations.jpg" alt="" title="A collection of user interface component sketches. The top left shows a simple UI flow for selecting an item from a list. Other components include a dropdown menu, a checkbox, and various sliders for adjusting values like &#39;Space,&#39; &#39;X,&#39; &#39;Y,&#39; and &#39;Angle.&#39; There are also different forms of input fields, buttons, and a circular color picker with a slider control. " decoding="async" width="1920" height="1440" /> </picture></p> <p>I think a ✓ meant I liked the overall thumbnail idea.</p> <h2> How it turned out <a name="how-it-turned-out" href="#how-it-turned-out">#</a> </h2> <p>Here&#39;s a quick video of a basic, responsive, 2 stop gradient line with a custom transition hint; shown on each linear, radial and conic overlay.</p> <p><video src="/media/gradient-line-demo.mp4" width="1282" height="586" alt="" preload="none" poster="/media/gradient-line-demo.avif" controls loop muted playsinline allowFullScreen /></p> <p>Sketches lined up pretty good!</p> <p>Well, I&#39;m not done with it yet! I do want to add layers and <code>background-image</code> sizing. I think it&#39;d make it the perfect tool for finely crafted gradients. Stay tuned!</p> Devtools Fm 151 - Adam Argyle https://nerdy.dev/devtools-fm-151?utm_source=rss 2025-08-25T16:46:37.000Z <img style="display: none" src="https://nerdy.dev/media/devtools-fm-151.jpg" alt="DevTools FM - Episode 151" height="500" width="1500" /> <p><span class="Tag">Ep #151</span><br><a href="https://devtools.fm/">DevTools FM</a> </p> <p>Join <a href="https://github.com/hipstersmoothie">Andrew</a>, <a href="https://github.com/Zephraph">Justin</a> and I for a chat about some of the developer tools I&#39;ve worked on.</p> <p><a href="https://open.spotify.com/show/142I2b9HGjWhRgPXhOYUnN">Listen</a> · <a href="https://www.youtube.com/watch?v=jF2eVe75eVQ">Watch</a> · <a href="https://www.devtools.fm/episode/151">Subscribe</a></p> Fix the Signal - Robin Rendle https://robinrendle.com/notes/fix-the-signal/ 2025-08-23T17:20:41.000Z <p>It often feels like optimism is an act of revenge, an act of spite or rebellion, because optimism requires diligence and effort whilst pessimism feels like the default, the thing requiring no energy or effort. Mike Monteiro wrote along similar lines in <a href="https://buttondown.com/monteiro/archive/how-to-stay-hopeful/">How to stay hopeful</a>:</p> <blockquote> <p>The problem with dystopias is that dystopias are easy. You simply stop giving a shit about things or people that you should give a shit about, or things that don’t affect you directly, thinking they’re somebody else’s problem and boom—shit starts getting dystopian real quick.</p> </blockquote> <p>On the flip side: optimism is utopian. The world can be better! The world <em>is</em> better! Sure, there’s a kind of optimism that makes you blind to the suffering of others, there’s cruelty in it sometimes. But there’s nothing but misery to be found in endless snark, in womp-wompism, in all-things-must-be-sad-all-the-time-ism. I fear recently I’ve slipped into that other way of seeing the world — I worry I’ve become a true bummer — perhaps because I’ve been listening and reading to too much of the wrong things, perhaps encouraging all the wrong signals.</p> <p>So let’s talk about a few things that make me optimistic about the world right now. Let’s fix the signal!</p> <h2 id="1.-hummingbirds!" tabindex="-1">1. Hummingbirds! <a class="direct-link" href="https://robinrendle.com/notes/fix-the-signal/#1.-hummingbirds!" aria-hidden="true">#</a></h2> <p>Each morning, just outside my office, two hummingbirds dance and play above the redwoods. They are tiny and oscillating, endlessly wagging their little bodies because I like to believe that they’re happy to see me at work behind the glass. Whilst their wings beat back and forth the <a href="https://en.wikipedia.org/wiki/Stroboscopic_effect">stroboscopic effect</a> kicks in, making them look like they’re hovering along the treetops without the help of their wings at all. At just the right angle it looks like these chaps have hacked the video game engine that powers our world and can now move in any direction with arms outstretched, as if they’ve both loaded incorrectly.</p> <p>These hummingbirds never fail to put me in a good mood, but I’m not entirely sure why. I suppose it’s the stark contrast from the world where I grew up — dreary, grey, pub-filled streets — and now there’s only the eternal blue of Cupertino skies above and the super-saturated trees flanking my office windows and now, here they are, they’ve come back to say hello.</p> <h2 id="2.-martyr!" tabindex="-1">2. Martyr! <a class="direct-link" href="https://robinrendle.com/notes/fix-the-signal/#2.-martyr!" aria-hidden="true">#</a></h2> <p>I know I’m late to the party but Kaveh Akbar’s <em>Martyr!</em> is great and I couldn’t put it down. The protagonist spends the whole novel fantasizing about a death worth living for, where he confronts and romanticizes his own suicide. Big portions of the book are taken up by his dreams:</p> <blockquote> <p>...the body offered you dreams. In exchange for a third of your living, you were offered sprawling feasts, exotic adventures, beautiful lovers, wings. Or at least the promise of them, made only slightly less intoxicating by the curious threat of nightmare. How sometimes, at random, your mind would decide to reduce you to a whimper, or a gasp, in the night.</p> </blockquote> <p>Kaveh snaps words together in a way that I find totally irresistible and un-put-downable. Whilst I was reading this book I had a terrible flu and each night I’d wake up in a cold sweat with the strangest dreams rolling around in my head. So it felt somewhat magic to finish the book and flu on the same day, with my dreams having then reset after the book’s spell had worn off.</p> <h2 id="3.-close-to-the-machine!" tabindex="-1">3. Close to the Machine! <a class="direct-link" href="https://robinrendle.com/notes/fix-the-signal/#3.-close-to-the-machine!" aria-hidden="true">#</a></h2> <p>It’s odd rereading Ellen Ullman’s <em>Close to the Machine</em> fifteen years later. On my first reading I honed in on the talk about computers, about software, about team work. I was lost in the rush of Ullman’s tale about living on the bleeding edge and fighting for great work to be done. I turned every page frantically as I hoped Ullman would find a problem worthy of her programming talents.</p> <p>Back then I wanted to <em>be</em> Ullman. I wanted to drive a convertible across a golden bridge, illuminated by magical software powers and money and the hard-earned wisdom that comes from struggling to smash computers and people together. I wanted to make something special.</p> <p>But now, after moving out to the Bay Area and a decade of failed relationships with startups and teams and endless software designs that never went anywhere, I see the underlying sadness of this little book. I see my own loneliness in there in ways I didn’t think could be put into words. I see my own failures and hopes and dreams in Ullman. I point at the book, DiCaprio style, when Ullman sells her soul, when she’s willing to start relationships with bitcoin boys despite knowing better, when she falls into the work in ways that’s difficult to pull herself back out again.</p> <p>Ullman is fallible in all the ways that I know I am, too. And that’s why I love this little book. It feels like something that shouldn’t be written down, something forbidden, something that upsets the natural order of software-as-a-job. And I still love it.</p> <h2 id="4.-herdling!" tabindex="-1">4. Herdling! <a class="direct-link" href="https://robinrendle.com/notes/fix-the-signal/#4.-herdling!" aria-hidden="true">#</a></h2> <p>I love <a href="https://herdling.game/">this little game</a>. I haven’t finished it yet, but already the music and storytelling-style have permanently etched itself into my noggin’. The game is about finding and traveling with a band of furry companions across a sad, flute-filled landscape. Rather unfortunately you can name each of your creatures and I decided to name them all after long-lost pets. This made the sweetness of this game extra sweet but at one point when we were all coming down a mountain together, all of them wagging their tales and shuffling their ridiculous bodies, I could see Lucy and Bob and Purdy and Crease and Lady again, galloping in formation. For the briefest moment I could see my little guys again.</p> <p>So: if anyone ever says that they caught me bawling my eyes out on my couch because of some big dumb videogame then I need you to know it’s all fake news, man. I never did any such thing. Now excuse me whilst I go find some big rocks to throw around and do ten thousand push ups. I have MAN things to do.</p> Post on Sara Soueidan – Blog - Sara Soueidan – Blog https://www.sarasoueidan.com/content/archived/focus-indicators--old/ 2025-08-18T08:41:01.000Z <p>Imagine you visit a website and you want to browse it for some content. You want to buy something; or maybe book a flight somewhere. And as you move your cursor onto the page, it suddenly disappears. Your hand may be still on the mouse, and you’re moving the mouse across the screen and across the page; but you can’t see where it is. You may or may not be hovering over a link or a button or any other form control at any moment. But if you <em>are</em> hovering over one, you don’t know which one it is. You could try clicking and then finding out, but you can probably already imagine what a nightmare of an experience you’re about to get into.</p> <p>Unfortunately, keyboard users experience the Web in a similarly frustrating manner too often. Their equivalent of a mouse cursor is usually hidden on too many websites, making it almost impossible for them to navigate those sites. A keyboard user’s cursor equivalent is the <strong>focus indicator</strong>. By designing and implementing accessible focus indicators, we can make our products accessible to keyboard users, as well as users of assistive technology that works <em>through</em> a keyboard or emulates keyboard functionality, such as voice control, switch controls, mouth sticks, and head wands, to mention a few.</p> <h2 id="what-exactly-is-a-focus-indicator%3F" tabindex="-1">What exactly <em>is</em> a focus indicator?</h2> <p>Keyboard users typically navigate their way through websites by pressing the <kbd>tab</kbd> key. This allows them to jump from one interactive element on the page to another.</p> <p>Just like mouse users, they need to be able to see where they are on a page as they Tab their way through it, otherwise they won’t be able to identify the elements they are interacting with. That’s what <strong>focus indicators</strong> are for.</p> <p>A focus indicator is a visual indicator that “highlights” the currently focused element. This visual indicator is commonly presented as an outline around the element. An outline takes the shape of its element, and since every element in CSS is a rectangle, an outline is, therefore, usually a rectangle drawn around an element.</p> <figure class="wide"> <video class="video-gif" controls="" src="https://www.sarasoueidan.com/content/assets/images/article--focus-indicators/mdn-focus-indicator.mp4" width="100%"> Sorry, your browser doesn't support embedded videos. </video> <figcaption>Navigating the Mozilla Developer Network (MDN) website using a keyboard. As you tab through the homepage, you can see a rectangular outline highlighting the currently focused element.</figcaption> </figure> <aside role="note">A focus indicator can also take other forms, but outlines are very common for several reasons. Outlines have an advantage over other visual indicators (such as borders or background colors, for example) in that they can be applied to the element without causing any significant changes to that element. And since an outline is not part of an element's box model, it does not affect the layout of that element, and will therefore not cause any layout shifts when it is applied. (That's also why outlines are preferred over borders for visualizing and debugging layouts 💡) In addition to that, outlines are preserved and used in Forced Color Modes such as Windows High Contrast Mode, where background colors, border colors, and box shadows are usually overridden by user and system styles.</aside> <p>So a focus indicator allows a keyboard user to see exactly where they are at any given moment. Without it, they wouldn’t know where they are on a page and they wouldn’t be able to navigate the page and operate its controls.</p> <p><strong>The focus indicator is to keyboard users what the mouse cursor is to mouse users.</strong> And just like you would never want to hide the mouse cursor, you never want to hide the focus indicator.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/laura-focus-slide.png" alt="Laura Carvajal on stage at Fronteers 2018, with a slide on screen behind her that says 'You wouldn't steal their cursor'" /> <figcaption>Laura Carvajal on stage at Fronteers conference 2018.</figcaption></figure> <p>In fact, <strong>a visible focus indicator</strong> is a requirement for a site to be considered accessible under the Web Content Accessibility Guidelines (WCAG). Removing or hiding focus indicators is a violation and will therefore fail <a href="https://www.w3.org/TR/WCAG22/#focus-visible">Success Criterion (SC) 2.4.7: Focus Visible (Level A)</a>, which states that:</p> <blockquote> <p>any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible.</p> </blockquote> <h2 id="browser-default-focus-styles" tabindex="-1">Browser default focus styles</h2> <p>Browsers provide focus indicators to native interactive elements out of the box, for free. And most of us—if not all—have at some point in time included this CSS snippet in their stylesheets:</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">:focus</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p>to remove those focus indicators applied by the browser.</p> <p>To meet the accessibility requirement, you should avoid removing the focus indicator provided by the browser <em>unless</em> you are replacing it with your own focus indicator. And I do recommend you do that.</p> <p>By preserving browser focus styles, you <em>may</em> meet the requirement of showing a visible focus indicator, but that may not be enough, because a focus indicator needs to be <em>clearly</em> visible to be considered accessible. And browser focus indicators may not always be.</p> <p>(What’s the benefit of <em>showing</em> an indicator that many users may not be able to <em>see</em>?)</p> <p>In order for a focus indicator to be clearly visible it needs to have a color contrast against adjacent colors that is high enough for users with moderately low vision to be able to discern it.</p> <p>The Web Content Accessibility Guidelines define the minimum color contrast ratio required for interactive components <strong>and their states</strong> to be accessible in SC <a href="https://www.w3.org/TR/WCAG21/#non-text-contrast">1.4.11 Non-Text Contrast</a>.</p> <p>Focus indicators on UI controls fall under the “non-text” components category, as they are used to identify a component’s state. To pass this criterion, our focus indicators <strong>must have a color contrast ratio of at least 3:1 against adjacent colors.</strong></p> <p>Default focus indicators provided by browsers may fail this criterion, depending on the colors you’re using on your page. You can end up with a usability problem if the colors of your page clash with the colors of the default focus indicators, making them difficult to see. When that happens, you’ll want to <em>override</em> those focus styles with better, more accessible ones.</p> <p>Here is a screenshot of how Chrome, Firefox, Microsoft Edge, and Safari style their respective focus indicators (at the time of writing) when applied to a <code>&lt;button&gt;</code>:</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/browser-focus-styles.png" alt="Screenshot showing a blue button on a white background with four different focus indicators as applied by Chrome, Firefox, Edge, and Safari." /></figure> <p>Chrome, Edge and Safari apply a 1-pixel solid outline. Firefox applies a 1-pixel dotted outline. As far as color contrast with the white background goes, they all pass the accessibility check. But the dotted outline in Firefox is still very difficult to discern compared to the other outlines, even though its color has enough contrast with the white background. This is because the contrasting <em>area</em> of the outline is not large enough. And that’s because the outline is very thin and dotted. We’ll come back to this shortly.</p> <p>On a black background, Firefox’s black focus indicator disappears, and Safari’s indicator has a contrast so low it will be extremely difficult to discern by most users.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/Browser-focus-styles-on-black.png" alt="Screenshot showing the blue button on a black background with four different focus indicators as applied by Chrome, Firefox, Edge, and Safari." /></figure> <p>Chrome and MS Edge, however, have something interesting happening in that they apply what looks like a <em>second</em> outline—a white outline around the first outline, that creates enough contrast on most darker backgrounds.</p> <aside role="note"> Chrome and Edge v94 and up provide more visible focus indicators that you can enable in their respective settings panes that you can access like this: <ul> <li>In Chrome, type this into the URL bar: <code>chrome://settings/accessibility</code></li> <li>In Edge (v94 and up), type this into the URL bar: <code>edge://settings/accessibility</code></li> </ul> <p>Then you can enable the more visible focus indicators by enabling the corresponding option in each panel:</p> <p>In Chrome, enable the “Show a quick highlight on the focused object” option.</p> <p>In edge, enable the “Show a high visibility outline around the area of focus on the page” option.</p> <p>When these options are on, you’ll notice an additional border as well as a box shadow around the focused elements.</p> <p>Firefox does not provide a similar option at the time being. But you can make the default dotted outline more visible by tweaking the style and width options in Firefox’s configuration pane.</p> <p>You can do that by navigating to <code>about:config</code>. Use the search bar within the config page to search for <code>focus_ring</code>. The search results will show two variables that you can tweak: <code>browser.display.focus_ring_style</code> and <code>browser.display.focus_ring_width</code>.</p> <p>If you set the style value to 0 and the width value to 4, you’ll get a thicker outline that more resembles the outline provided in Chrome and Safari by default.</p> </aside> <p>So while you <em>may</em> get away with using the default browser focus styles to meet WCAG 2.1 requirements and call it a day, it is generally a good idea that you <strong>override the default styles with more accessible ones.</strong> In fact, in <a href="https://www.w3.org/TR/WCAG22/">WCAG 2.2</a>, it becomes necessary to do that, because the requirements get more specific, and as you’ll see in the following sections, browser focus indicators will often fail the new requirements.</p> <p>In what follows, we’re going to get a little nerdy!</p> <h2 id="new-focus-indicator-accessibility-requirements-in-wcag-2.2" tabindex="-1">New focus indicator accessibility requirements in WCAG 2.2</h2> <p>In <a href="https://www.w3.org/TR/WCAG22/">WCAG 2.2</a>, three new success criteria were added to define <em>how accessible</em> a focus indicator is depending on its <strong>color, area, and visibility</strong>:</p> <ul> <li>SC <strong>2.4.11 Focus Appearance</strong> (Level AA),</li> <li>SC <strong>2.4.12 Focus Not Obscured (Minimum)</strong> (Level AA), and</li> <li>SC <strong>2.4.13 Focus Not Obscured (Enhanced)</strong> (level AAA)</li> </ul> <p>These new criteria aim to ensure that a keyboard focus indicator is <strong>clearly visible and discernible</strong>, and they provide the conditions to ensure that. These criteria specify <strong>a minimum area</strong> required for the focus indicator to be considered accessible, taking into account its <strong>color contrast ratio</strong> relative to its initial color, as well as against adjacent colors within the focused component.</p> <p>We’re going to dive into these requirements and how to meet them in the following sections.</p> <p>We’ll start with <strong>SC 2.4.11 Focus Appearance</strong> which states that:</p> <blockquote> <p>When the keyboard focus indicator is visible, one or both of the following are true:</p> <ol> <li>The entire focus indicator meets all the following:</li> </ol> <ul> <li>encloses the user interface component or sub-component that is focused, and</li> <li>has a contrast ratio of at least 3:1 between the same pixels in the focused and unfocused states, and</li> <li>has a contrast ratio of at least 3:1 against adjacent non-focus-indicator colors.</li> </ul> <ol start="2"> <li>An area of the focus indicator meets all the following:</li> </ol> <ul> <li>is at least as large as the area of a 1 CSS pixel thick perimeter of the unfocused component or sub-component, or is at least as large as a 4 CSS pixel thick line along the shortest side of the minimum bounding box of the unfocused component or sub-component, and</li> <li>has a contrast ratio of at least 3:1 between the same pixels in the focused and unfocused states, and</li> <li>has a contrast ratio of at least 3:1 against adjacent non-focus-indicator colors, or is no thinner than 2 CSS pixels.</li> </ul> <p>Exceptions:</p> <ul> <li>The focus indicator is determined by the user agent and cannot be adjusted by the author, or</li> <li>The focus indicator and the indicator’s background color are not modified by the author.</li> </ul> </blockquote> <p>For most of the examples, we’ll be demonstrating and examining the focus indicator requirements when applied to a blue button set on a white background.</p> <p>To start, we’re going to define two terms that will help us understand these requirements: the <strong>focus indication area</strong>, and the <strong>contrasting area</strong>. (These terms were introduced in previous versions of the Success Criteria and have been edited out in the final wording. But I think they are helpful in understanding the requirements.)</p> <h3 id="1.-the-focus-indication-area-and-the-contrasting-area" tabindex="-1">1. The focus indication area and the contrasting area</h3> <p>When a component changes on focus to include a focus indicator, that change can always be measured as a change of color contrast.</p> <p>If you add a black outline around the blue button, the change of color between the unfocused and focused states is from white to black. That’s because <strong>the area— the pixels on the screen —that has changed color</strong> in the focused state is the area <em>around</em> the button. That area was initially white, and it changed to black when the button received focus. This area is called <strong>the focus indication area.</strong></p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/focus-indication-area-1.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a thick black outline around it. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the focus indication area." /></figure> <p>The focus indication area is the area in square CSS pixels where the change in color <!--contrast--> between the focused and unfocused states of the component happens.</p> <p>For a focus indicator to be accessible, it is required to have <strong>an area of the focus indication area</strong> (a <em>subset</em> of the focus indication area) that has <strong>a minimum contrast ratio of 3:1</strong> between the colors in the focused and unfocused states. That area is called <strong>the contrasting area</strong>.</p> <p>In other words, the contrasting area is the area of the focus indication area that has at least a 3:1 contrast ratio with the colors of the unfocused state. And <strong>the contrasting area may or may not be equal to the entire focus indication area.</strong></p> <p>In the previous example, the color change happens from a solid white to a solid black, and the color contrast ratio between the unfocused and focused state (white and black) is <strong>21</strong>:1. So the entire focus indication area meets the minimum contrast requirement. This means that the contrasting area is equal to the entire focus indication area.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/contrasting-area-1.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a thick black outline around it. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area." /></figure> <p>Similarly, if you add a black outline that is separated from the button, once again, the area that exhibits the change in color is the contrasting area.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/contrasting-area-2.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a separated thick black outline. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area." /></figure> <p>(I like this pattern because it adds some breathing room and helps the focus indicator stand out, making it easier to see.)</p> <p>If you add an outline inside the button itself, the contrasting area then lies inside the button. The change of color is from blue (the button’s background color) to black. The color contrast ratio between the focused and unfocused state is <strong>4.86</strong>:1.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/contrasting-area-3.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with an inner thick black outline. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area." /></figure> <p>If the button changes its background color from blue to black on focus, then the entire button’s background area is the contrasting area, and the color contrast ratio between the focused and unfocused state is once again <strong>4.86</strong>:1.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/contrasting-area-4.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the button in its focused state, having a black background instead of blue. On the right, is a button with with a pattern applied to its background area, indicating that this patterned area is the contrasting area." /></figure> <p>When the focus indicator is a solid color, measuring the color contrast ratio in the contrasting area is straightforward. But color changes may not always be solid. You may want to indicate focus on the button by applying a gradient drop shadow to it. In this case, <strong>only the portion of the gradient with sufficient contrast (larger than 3:1) will be our contrasting area</strong>; the remaining portion that fails will not be a part of it. This is an example of when the contrasting area is smaller than the focus indication area.</p> <p>You may need to take some spot-checks on the gradient area and establish what area meets the contrast requirement.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/gradient-contrast.jpg" alt="Illustration: On the left is a blue button with a white label in its default, unfocused state. Next to it on the right is the blue button with a translucent black drop shadow as the focus indication area. On the right, is a button with the same drop shadow minus the parts of the drop shadow that don't pass the minimum contrast requirement, indicating that the remaining area (that does pass) is the contrasting area." /></figure> <p><strong>The greater the change of contrast between the unfocused and focused states, the easier it is for users to see it.</strong></p> <hr /> <p>In addition to requiring a minimum contrast in the contrasting area, a focus indicator is required to have <em>a minimum surface area</em> for the contrasting area as well. In other words, the contrasting area needs to be large enough to be considered accessible. But how much is large <em>enough</em>?</p> <h3 id="2.-minimum-contrasting-area" tabindex="-1">2. Minimum contrasting area</h3> <p>Remember how we said that Firefox’s dotted outline was difficult to discern even though its contrasting area had a high contrast ratio with the background? I mentioned that that’s because its area was small, due to the outline being thin and dotted. The main issue here lies in the fact that it is <em>dotted</em>. The gaps in the line decrease the overall area of the focus indicator, making it difficult to see.</p> <p><strong>The bigger the visible change when the component receives focus, the easier it is to see.</strong> And to ensure that focus indicators have good visibility, 2.4.11 requires <strong>a minimum surface area</strong> for the contrasting area. That is, the contrasting area needs to be larger than a specified minimum.</p> <p>The SC states that:</p> <blockquote> <p>The entire focus indicator encloses the user interface component or sub-component that is focused [ or ] An area of the focus indicator is at least as large as the area of a 1 CSS pixel thick perimeter of the unfocused component or sub-component, or is at least as large as a 4 CSS pixel thick line along the shortest side of the minimum bounding box of the unfocused component or sub-component</p> </blockquote> <p>To “enclose” a component means to “solidly bound or surround”. Bounding is derived from the “bounding box” of an element. The bounding box of a component is the smallest possible <em>rectangle</em> that entirely encloses it and its descendants. Surrounding is kind of like “wrapping” a shape. The difference between bounding and surrounding is illustrated in the two images of a set of ratings stars.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/bound-vs-surround.png" alt="Two sets of star ratings. In both sets, the same three stars have been selected, and the focus indicator is visible on the third star. In the first set, the focus indicator is a rectangular outline bounding the star. In the second set, the focus indicator is a star-shaped solid outline that surrounds the star." /> <figcaption> In the first image, the focus indicator solidly <em>bounds</em> the star. In the second image, the focus indicator (also a solid outline) <em>surrounds</em> the star. (<a href="https://w3c.github.io/wcag/understanding/focus-appearance.html">Image Source</a>) </figcaption> </figure> <p>The first point in the criterion is technically a special case of the second condition.</p> <p>A focus indicator that encloses a component is a focus indicator that <em>solidly bounds or surrounds</em> the component. A solid outline is an example of a focus indicator that solidly bounds an element. And solid 1px outline has an area of at least 1px thick perimeter of the component. (Of course, any outline thicker than 1px will also meet the area requirement.)</p> <p>If the focus indicator is dotted or dashed (not solid), it no longer ‘solidly bounds or surrounds’ the component and will therefore need to meet the condition defined in the second point.</p> <p>The second point determines the minimum contrasting area using the perimeter of the component.</p> <p>The perimeter of a rectangle is equal to a line that’s 2 times the width plus 2 times the height minus the shared corner pixels which are equal to 4 pixels: <strong>Perimeter § = 2<em>h + 2</em>w - 4</strong>.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/area-calcs.jpg" alt="Illustration: On the left is the blue button with annotations for the long and short sides of the button. On the right, is the button with width and height annotations, and text that calculates the perimeter of the button: Perimeter (P) = 2*height + 2*width - 4" /></figure> <p>The perimeter of a circle is <strong>2𝜋r</strong>, where <strong>r</strong> is the radius of that circle.</p> <p>Firefox’s focus indicator is equal to the length of the perimeter of the button <em>minus</em> all the gap spaces introduced by using the dotted style. The resulting length is approximately half of the perimeter. To fix it, the outline thickness can be doubled to make up for the area that is lost in the gaps. Here’s what the dotted outline looks like with 2px and 3px thicknesses. <strong>The thicker the outline, the larger its surface area, and the easier it is to see.</strong></p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/firefox-outline.jpg" alt="Illustration: the blue button on the left with Firefox's default 1px dotted outline. In the middle is the same button with Firefox's dotted outline at 2px thickness. And on the right is the button with a 3px-thick dotted outline." /></figure> <p>Now let’s assume, for demonstration purposes, that we’re designing focus styles for a <strong>150px</strong> by <strong>75px</strong> button. The perimeter of this button is: 150px + 150px + 75px + 75px - 4px = <strong>446px</strong>.</p> <p>When we apply an <em>inner</em> outline to the button, this outline is going to be smaller than the perimeter of the button (because the outline’s width and height are shorter than the button’s width and height). Once again, increasing the thickness of the outline will make up for the area lost by placing the outline inside the button.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/outline-area.jpg" alt="Illustration: On the left: the blue button with a 1px thin inner black outline. And text indicating that this outline fails. On the right: the blue button with a 2px thick inner outline, and text indicating that this outline passes." /> <figcaption>A 130px by 55px outline inside the button will have a surface area of 366px, which is smaller than our perimeter's 446px area. By doubling the thickness of the outline, its surface area becomes 732px, which is larger than the perimeter and therefore meets the minimum area requirement.</figcaption></figure> <p>Similarly, for a contrasting area in a gradient focus indicator, you’ll want to calculate the component’s perimeter and compare the contrasting area to that of the perimeter.</p> <p>In the following image is a circle with a 22px radius and 138px perimeter.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/circle-perimeter-example.jpg" alt="Illustration: a circular button with a magnifier (search) icon as a visual label. Three variations of the button, each with a different focus indicator (1), (2), and (3). (1) is a 1px solid separated circular outline. (2) is a 1px solid circular inner outline. And (3) is a 3px thick inner circular outline." /></figure> <p>On the top right, the focus indicator (1) is a 1px solid circular outline. The perimeter of the focus indicator is 172px, which is larger than 138px. With a color contrast change that is higher than the minimum requirement, this indicator passes the accessibility requirement.</p> <p>On the bottom left, focus indicator (2) is an inner 1px solid outline with enough color contrast change, but an area (113px) smaller than the circle’s perimeter. This indicator does not pass the requirements.</p> <p>And finally on the bottom right, the focus indicator (3) is an inner 2px thick outline. This outline has a double the area of focus indicator (2) (226px), making it larger than the perimeter of the circle, so it passes the minimum area requirement.</p> <hr /> <p>In addition to the minimum area requirement that is based on the component’s perimeter, the success criterion also provides <strong>a secondary minimum</strong> based on the shortest side of the component:</p> <blockquote> <p>or is at least as large as the area of a 4px thick line along the shortest side of the component’s minimum bounding box</p> </blockquote> <p>Instead of aiming for a minimum area of 1px thick perimeter, you could aim for a 4px thick line along the shortest side of the component’s bounding box.</p> <p>The secondary minimum area can be useful for when you have a list of focusable items stacked on top of each other, such as links in a vertical navigation or a drop-down menu. The focus indicator on a link in the drop-down could be a 4px thick border along the shortest side (typically the height) of the link as shown in the image below.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/4px-outline.jpg" alt="A list of vertically-stacked menu items in their unfocused state (left). On the right is the list with a 4px thick focus indicator applied to the left edge (shortest side) of one of the list items." /></figure> <p>The thicker the line, the larger the contrasting area, the more visible the focus indicator is. Obviously, the 4px thick line along the shortest side of the element is <em>a minimum</em>. A border along the longest side would also meet the requirement (assuming the thickness ensures a large enough area). My point is that, while I am giving simple and specific examples, my goal is to demonstrate the requirements. But you have the creative freedom to choose any focus indicator style you prefer that meets the accessibility requirements.</p> <p>The main goal of the minimum area requirement is to ensure that the focus indicator is easier to see. Whetever the style you choose to indicate focus, the important thing is to ensure that the contrasting area meets the minimum area requirement(s), so that it can be easily seen.</p> <h3 id="3.-contrast-with-adjacent-colors-in-the-component" tabindex="-1">3. Contrast with adjacent colors in the component</h3> <p>In addition to requiring a minimum contrast ratio 3:1 and a minimum surface area, the contrasting area also needs to be easily distinguishable from <strong>adjacent colors</strong> within the focused component.</p> <p>This is accomplished either by</p> <ul> <li>ensuring <strong>at least 3:1 contrast ratio between the contrasting area and adjacent colors</strong>, <em>or</em></li> <li>ensuring the contrasting area has <strong>a thickness no less than 2px.</strong></li> </ul> <p>We’ll start with the blue button again as an example, and apply a simple 1px (external) outline to indicate focus. But this time, I’m changing the color of the outline from black to a darker shade of the blue background.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/adjacent-contrast-fail.jpg" alt="On the left, the blue button in its default, unfocused state. On the right is the blue button with a 1px thick dark blue outline applied to it." /> <figcaption> The button’s background color is: `#314cff`. And the outline color is: `#1100cd`. </figcaption></figure> <p>The contrasting area’s contrast ratio (dark blue versus the white background) is: <strong>11.02</strong>:1. And its area is larger than the button’s perimeter. So the outline color and area pass the minimum contrasting area requirements that we discussed earlier.</p> <p>But the dark blue color of the outline has a low contrast ratio <strong>against the adjacent blue</strong> used in the background of the button: 1.89:1. So while this outline meets the first two accessibility requirements, it fails the third one.</p> <p>To fix it, we can either</p> <ul> <li><strong>choose a different outline color that has at least 3:1 contrast ratio</strong> against the button’s background color (like black <code>#000</code>, for example), <strong>or</strong></li> <li><strong>increase the thickness of the outline.</strong> Any thickness greater than or equal to 2px will do.</li> </ul> <p>We <em>can</em> also fix the low adjacent contrast by <strong>separating the outline from the button</strong>, so the outline’s adjacent color becomes white (the page background), and would therefore meet the color contrast requirement.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/adjacent-contrast-pass.png" alt="On the left is the blue button with a black 1px solid outline, and text that says 'Pass' underneath it. In the middle, is the blue button with a 2px thick dark blue outline, and text that says 'Pass'. On the right is the blue button with a 1px dark blue outline separated from the button's edges, and text that says 'Pass'." /></figure> <h3 id="4.-the-focused-element-cannot-be-fully-obscured" tabindex="-1">4. The focused element cannot be fully obscured</h3> <p>The goal of a focus indicator is to allow the user to see and know where they are on a page, by making the currently active element more visible to their eye.</p> <p>But what good is a focus indicator if the focused element itself is not visible because it’s hidden off-screen or obscured by other elements on the page?</p> <p>SC <strong>2.4.12 Focus Not Obscured (Minimum)</strong> states that:</p> <blockquote> <p>When a user interface component receives keyboard focus, the component is not entirely hidden due to author-created content.</p> </blockquote> <p>Simply put: you want to make sure the user can actually see the component that they’re focusing on, by making sure it’s not hidden behind other content on the page.</p> <p>That being said, this criterion requires that the component be <q>not entirely hidden</q>. This does imply that it could be partially hidden, as long as it’s still partially visible.</p> <p>SC <strong>2.4.13 Focus Not Obscured (Enhanced)</strong> (which is the level AAA version of this requirement) states that:</p> <blockquote> <p>When a user interface component receives keyboard focus, no part of the focus indicator is hidden by author-created content.</p> </blockquote> <p>When aiming for Level AA conformance, you may get away with partially hiding the focused component, though I can’t imagine where or how that would not be problematic. I recommend that you <strong>always make sure focused component is <em>entirely</em> visible</strong> and not obscured by other content. It’s just better for usability. SC 2.4.13 is one of the AAA-level criteria that are also fairly easy to meet, even if you’re not aiming to be AAA-compliant.</p> <p>You may wonder if this requirement makes Skip links inaccessible. It doesn’t. Because Skip links are designed so that they are <strong>visible when they receive focus</strong>; so the user <em>is</em> able to see what they are focusing on when they focus on the skip link.</p> <p>A very common pattern that is more likely to fail this criterion on many websites is off-canvas navigation and other drop-down and fly-out components. Links in drop-down or off-canvas navigations are only meant to be interactive when they are visible. If you want to click on a link, you open the navigation, the links become visible, and you can click on the link you need and go where you need to go.</p> <p>Keyboard users sometimes experience these navigation patterns differently when they are implemented inaccessibly. They’ll navigate through a page and suddenly notice their focus indicator disappear. They may continue tabbing, until at some point the indicator finally re-appears and continues to the next visible link.</p> <p>This happens because the links that are hidden off-screen or inside dropdowns are <strong>only visually hidden</strong>, but are still accessible via keyboard. This results in a mismatch between the visual and keyboard experiences of a keyboard user: they’re tabbing through links and components that they are not seeing on screen.</p> <p>To avoid this happening, make sure that components that are not meant to be visibly interactive are properly hidden, by making them inert, for example.</p> <h2 id="recap" tabindex="-1">Recap</h2> <p>So theses are the accessibility requirements for focus indicators to pass WCAG.</p> <ul> <li>There is an area of the focus indicator that has a contrast ratio of at least 3:1 between the colors in the focused and unfocused states. (This is the focus indicator’s contrasting area.)</li> <li>The contrasting area needs to be at least as large as: <ul> <li>the area of a 1px thick perimeter of the component, or</li> <li>the area of a 4px thick line along the shortest side of the component’s minimum bounding box</li> </ul> </li> <li>The contrasting area has a contrast ratio of at least 3:1 against adjacent colors in the focused component, or the contrasting area has a thickness of at least 2px</li> <li>The focused element is not obscured by other elements on the page.</li> </ul> <p>With these requirements in mind, we now know that Firefox’s button focus indicator that we saw earlier fails the minimum contrasting area requirement. Chrome and Edge’s current focus indicators would fail the adjacent contrast requirement if your button has a background color that clashes with the outline’s color. And Safari’s focus indicator will also fail the minimum contrast ratio requirements also depending on the colors you use inside and outside the button.</p> <p>These browsers may also apply different focus indicators to different interactive elements, which may also fail at least one of the accessibility requirements, depending on your color palette.</p> <p>So <strong>I highly recommend overriding the default focus indicators with custom, more accessible ones.</strong> This also gives you the creative freedom to design focus indicators that look nicer on your components than the ones provided by the browser.</p> <p>Knowing what makes a focus indicator accessible, we can examine our own as well as the focus indicators of popular design systems and UI pattern libraries, and determine which ones pass WCAG criteria and which ones don’t
</p> <h2 id="examining-the-accessibility-of-focus-indicators-in-popular-design-systems-and-ui-pattern-libraries" tabindex="-1">Examining the accessibility of focus indicators in popular design systems and UI pattern libraries</h2> <p><a href="https://material.io/components/buttons">Material design button</a> focus indicator is a change in background color, in addition to an elevation effect created by extending the box shadow underneath the button. This focus indicator <strong>fails</strong> the accessibility requirements because of a very low change in contrast (<strong>1.53</strong>:1) between the focused and unfocused states.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/material-design-button.jpg" alt="A button from Material Design's component library in its default unfocused state on the left, and its focused state on the right. When unfocused, the button has a navy blue background color. In its focused state, the background color becomes purple." style="max-width: 100%; width:500px;" /> <figcaption>Material Design’s button focus indicators fail WCAG requirements for accessibility.</figcaption></figure> <p><a href="https://getbootstrap.com/docs/4.0/components/buttons/">Bootstrap 4 buttons</a> also fail WCAG requirements because of low change in contrast between the focused and unfocused states. For example, the change in contrast on the blue button is <strong>1.92</strong>:1.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/bootstrap-4-buttons.jpg" alt="A screenshot of buttons from Bootstrap 4's component library in their unfocused state. Below it, is a screenshot of those buttons with their focus indicators visible. The focus indicators are 2px or 3px-thick outlines with lighter versions of the colors used in their backgrounds." /><figcaption>Bootstrap 4’s button focus indicators also fail WCAG requirements for accessibility.</figcaption></figure> <p><a href="https://material-ui.com/components/checkboxes/#basic-checkboxes">Material UI Checkboxes</a> get a large focus indicator area, but the color contrast change is also low (<strong>1.58</strong>:1).</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/Material-ui-checkbox.jpg" alt="On the left: a Material UI checkbox in its unfocused state. The checkbox (in its checked state) has a red background and a white checkmark. On the right is the checkbox in its focused state, showing a large focus indicator. The focus indicator is a large circle with a light red background color." style="max-width: 100%; width:350px;" /><figcaption>Material UI’s checkbox focus indicator fails WCAG requirements for accessibility.</figcaption></figure> <p><a href="https://www.gov.uk/">GOV.UK</a> is one of the most accessibility-compliant websites I know. So I was curious to see how their focus indicators measure against WCAG 2.2 requirements.</p> <p>When focused, the links get a thick underline as well as a change in background color from white to yellow. While the yellow does not pass the minimum color contrast requirement, the indicator still passes accessibility requirements with the thick border compensating for that. (Note: A focus indicator that is larger than the minimum area may have parts that do not meet the 3:1 contrast ratio, as long as an area equal to the minimum does meet the contrast ratio.)</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/govuk-link.jpg" alt="On the left, a link in its default, unfocused state. The link has a blue color and an underline. On the right is the same link in its focused state. The link's focus indicator is a yellow background color behind the text, as well as a thick black underline." /><figcaption>GOV.UK’s link focus indicator passes WCAG requirements for accessibility.</figcaption></figure> <p>The text field on the <a href="http://gov.uk/">GOV.UK</a> homepage gets a 3px solid yellow outline as a focus indicator. This yellow outline has a contrast change (<strong>3.86</strong>:1) that’s higher than the requirement minimum (for a pixel color change from blue to yellow). The yellow color does not contrast with the input’s white background enough (adjacent contrast), but it is 3px thick, which compensates for that. So this focus indicator passes WCAG requirements.</p> <figure class=""><img src="https://www.sarasoueidan.com/assets/images/article--focus-indicators/govuk-text-input.jpg" alt="On the left: screenshot of a text input as seen on the GOV.UK homepage. The background behind the content is a shade of blue. The text input has a white background and no border. On the right, the text input in its focused state. The focus indicator is a 3px thick yellow outline around the input." /><figcaption>GOV.UK’s text input focus indicator (on the homepage) passes WCAG requirements for accessibility.</figcaption></figure> <h2 id="showing-the-focus-indicators-only-for-keyboard-users" tabindex="-1">Showing the focus indicators only for keyboard users</h2> <p>The main argument I usually hear <em>against</em> focus styles is that they appear even when you don’t want them to, such as when you click on the component with a mouse ot tap on it. Designers and stakeholders are usually not very fond of that. I remember a client once reporting “a bug” and telling me that mouse clicks are “kinda broken” because a thick outline appears when they clicked on links and buttons on the page. When that happens, I usually start a discussion about what focus styles are, why they are important, and why we should keep them. And then I’d always try to make a case for preserving them and “compromising aesthetics” for the sake of usability and accessibility. I didn’t always win those discussions.</p> <p>Today, I have those arguments far less. While I still find myself asking for focus styles in design specs, I don’t need to argue my way into including them in the final product.</p> <p>CSS enables us to show focus styles for keyboard users and hide them for all other users. So when you click an interactive element, the focus styles won’t show up and “ruin the aesthestics” anymore. Anyone navigating the page with a keyboard will appreciate the visual aid, and those who aren’t using a keyboard won’t even know they’re there!</p> <p>Browsers used to show their focus indicators on click (or tap), too. That’s why we used to include the “focus reset” rule in our style sheets:</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token comment">/* don't do this */</span></span><br /><span class="highlight-line"><span class="token selector">*:focus</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p>Today, all modern browsers only show focus indicators when they are needed: for keyboard users. The focus outline doesn’t show up when you click or tap an element; it only shows up when you tab to it with a keyboard.</p> <p>When you create your own custom focus indicators, you probably want to do the same and only show them for users who need them.</p> <p>You can do that using the <code>:focus-visible</code> pseudo-class.</p> <p><code>:focus-visible</code> does exactly the same thing <code>:focus</code> does, except that it only applies the focus indicator styles to an element when that element receives <em>keyboard focus</em>.</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token comment">/* applies a black outline to links only when focused via keyboard */</span></span><br /><span class="highlight-line"><span class="token selector">a:focus-visible</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">outline</span><span class="token punctuation">:</span> 2px solid black<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p><a href="https://caniuse.com/css-focus-visible">Browser support for <code>:focus-visible</code></a> is pretty good — pretty much all modern browsers support it today. So you may want to use <a href="https://github.com/WICG/focus-visible">the focus-visible polyfill</a> if you need to hide the focus indicator on older browsers. The polyfill works by adding a <code>focus-visible</code> class to the focused element, in situations in which the <code>:focus-visible</code> pseudo-selector should match.</p> <p>In your CSS, you can then use the class name added by the polyfill to target the focused element and apply the same focus styles you apply using the <code>:focus-visible</code> pseudo-class:</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">.js-focus-visible :focus:not(.focus-visible)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p>You can also skip the polyfill altogether and use <code>:focus-visible</code> as an enhancement on top of <code>:focus</code>.</p> <p>In his article about <a href="https://developer.paciellogroup.com/blog/2018/03/focus-visible-and-backwards-compatibility/"><code>:focus-visible</code> and backwards compatibility</a>, Patrick Lauke suggests a clever way to use <code>:focus-visible</code> today as part of a progressive enhancement strategy.</p> <p>The solution Patrick suggests is to use the <code>:not()</code> negation pseudo-class, and to (paradoxically) define styles not for <code>:focus-visible</code>, but to undo <code>:focus</code> styles when it is absent, and then using <code>:focus-visible</code> if we wanted to provide additional stronger styles for browsers that support it.</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">button:focus</span> <span class="token punctuation">{</span> </span><br /><span class="highlight-line"> <span class="token comment">/* some exciting button focus styles */</span> </span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token selector">button:focus:not(:focus-visible)</span> <span class="token punctuation">{</span></span><br /> <span class="token comment">/* undo all the above focused button styles<br /><span class="highlight-line"></span><br /><span class="highlight-line"> if the button has focus but the browser wouldn't normally</span><br /><span class="highlight-line"></span><br /> show default focus styles */</span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token selector">button:focus-visible</span> <span class="token punctuation">{</span> </span><br /><span class="highlight-line"> <span class="token comment">/* some even *more* exciting button focus styles */</span> </span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p><code>button:focus:not(:focus-visible)</code> is CSS for “when the button receives focus that is not focus-visible”. That is, “when the button receives focus that is not keyboard focus”. In other words, “when the button receives focus that is mouse focus, for example”. When that happens, undo all the <code>:focus</code> styles. Then apply keyboard-only focus styles using <code>button:focus-visible</code>.</p> <p>As Patrick notes, <q>this works even in browsers that don’t support <code>:focus-visible</code> because although <code>:not()</code> supports pseudo-classes as part of its selector list, browsers will ignore the whole thing when using a pseudo-class they don’t understand/support, meaning the entire <code>button:focus:not(:focus-visible) { ... }</code> block is never applied.</q></p> <p>I have a VSCode snippet set up that I use to quickly create these rulesets in my stylesheets, with sensible defaults that I find myself repeating across projects most of the time.</p> <p>I’ll end this section with this paragraph from Patrick’s article (emphasis mine):</p> <blockquote> <p>If you care about backwards compatibility (and you should, <strong><em>until you can absolutely guarantee without any doubt that all your users will have a browser that supports</em></strong> <strong><em>:focus-visible</em></strong>), you will always have to either polyfill or use the combination of <code>:focus</code> and <code>:not(:focus-visible)</code> (plus optional even stronger <code>:focus-visible</code>).</p> </blockquote> <h2 id="tips-for-styling-focus-indicators" tabindex="-1">Tips for styling focus indicators</h2> <p>Focus indicators have a purpose, so do what you can do to ensure that they serve that purpose well. They are meant to improve our users’ experience. The user couldn’t care less about the aesthetics of focus styles as long as they help them do what they are visiting your site to do.</p> <p>I like to create focus indicators that stand out. The more visible they are, the less the user needs to look for them, the better.</p> <p>You can get creative and create <strong>patterned focus indicators</strong> which have that extra benefit of not relying on color alone to convey state. Just remember to make sure they meet the minimum contrast and area requirements.</p> <p>We can also learn something from the way Edge and Chrome handle focus styles. Maybe create “double outlines” that play well in various color environments, or when you support both light and dark UI user preferences. In the future, the new <a href="https://www.w3.org/TR/css-color-5/#colorcontrast">the CSS <code>color-contrast()</code> function</a> can come in handy to create a sensible default focus style for most components. In fact, <code>color-contrast()</code> will come in handy for a lot of accessible color design in the future.</p> <p><strong>Avoid relying on background colors and box shadows alone to indicate focus.</strong> Forced Color Modes and other <a href="https://www.a11yproject.com/posts/2020-01-23-operating-system-and-browser-accessibility-display-modes/">accessibility display modes</a> will override and/or remove them. Outlines, on the other hand, will not be removed and would always be visible; and the browser will apply the display mode’s custom colors to style them.</p> <p>You <em>can</em> use backgrounds, borders and box shadows to style focus states. But if you do, add a transparent outline as a “fallback” for the various display modes:</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">button:focus-visible</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token comment">/* Default. Will be removed in Forced Color Modes */</span></span><br /><span class="highlight-line"> <span class="token property">box-shadow</span><span class="token punctuation">:</span> 5px 5px 7px <span class="token function">rgba</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token comment">/* Fallback. Will be visible with custom system colors in Forced Color Modes */</span></span><br /><span class="highlight-line"> <span class="token property">outline</span><span class="token punctuation">:</span> 1px solid transparent<span class="token punctuation">;</span> </span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p><strong>Focus indicators can also be animated.</strong> Background colors, borders, box shadows, and outlines can all be animated using CSS transitions and animations. The <code>outline-width</code> and <code>outline-offset</code> properties take numerical values that can be animated. So you can apply a subtle transition to your focus indicators to make them pop. Just make sure to wrap any transitions or animations in a <code>prefers-reduced-motion</code> user query, so users have the option to opt out of the animations if they want to.</p> <p>When you’re designing and working with a color palette, you can find a color that has enough contrast with the other colors in your palette and use it to style your focus indicators. If there is no one color that meets that criterion, you can add one, or design focus styles that work for different elements and the contexts in which they appear.</p> <p>You can use a color contrast tool like <a href="https://www.getstark.co/">Stark</a> to quickly check the contrast of two colors without interrupting your workflow — whether you’re designing in a design tool like Figma or in the browser. You can also use the browser devtools to check color contrast where they are available, or an online tool like <a href="https://webaim.org/resources/contrastchecker/">WebAIM’s color contrast checker</a>, which I used to calculate the color contrasts throughout this article.</p> <p><strong>Not all elements need to have the same focus style.</strong> I personally try to keep focus indicators visually consistent as much as possible. But there are times when some elements could benefit from a different focus style, whether for aesthetic or usability purposes—or maybe even both! Get creative, but do so within the boundaries of accessibility. Creating nice focus indicators is a nice touch that not only shows your attention to detail, but it also shows that you care about <em>all</em> of your user’s experiences enough to spend a bit of time fine-tuning these details.</p> <h2 id="outro" tabindex="-1">Outro</h2> <p>Designing accessible focus indicators is easier now that there are specific criteria to measure accessibility against.</p> <p>If you’re a designer, make a habit to design and include focus indicator styles in your design specs if you don’t already do so.</p> <p>If you’re a developer, include focus styles in your CSS defaults. If you’re working with designers, strike up a discussion about focus styles with them if they don’t already prioritize them in design specs.</p> <p>Sometimes, you don’t need permission, extra time, or extra budget to improve the accessibility and usability of your product. Focus indicators are one small yet critical addition to your product that has tremendous usability benefits. Spending a few extra minutes designing and adding them will pay dividends and improve your product for millions of people who will use it.</p> <h2 id="resources%2C-references-and-further-reading" tabindex="-1">Resources, references and further reading</h2> <ul> <li><a href="https://hiddedevries.nl/en/blog/2019-06-06-indicating-focus-to-improve-accessibility">Indicating focus to improve accessibility</a></li> <li><a href="https://alastairc.uk/tests/wcag22-examples/focus-visible-enh-examples.html">Focus visible enhanced examples</a></li> <li><a href="https://developer.paciellogroup.com/blog/2018/03/focus-visible-and-backwards-compatibility/"><code>:focus-visible</code> and backwards compatibility</a></li> <li><a href="https://css-tricks.com/focusing-on-focus-styles/">Focusing on Focus Styles</a></li> </ul> <!--Alastair Campbell, one of the editors of WCAG 2.2, has also examined the accessibility of focus indicators on a bunch of websites and [shared his findings](https://alastairc.uk/tests/wcag22-examples/focus-visible-enh-examples.html). Seeing how more different focus indicators have passed or failed WCAG criteria is helpful in gaining a clearer understanding of the criteria. So I recommend checking his findings out if you need. --> CSS Carousels – Revisited - Sara Soueidan – Blog https://www.sarasoueidan.com/blog/css-carousels-revisited/ 2025-08-18T08:41:01.000Z <p>Update: Blink: Intent to Ship: CSS counter() and counters() in alt text of ‘content’ property — potentially useful for providing alt text for CSS-generated scroll markers.</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"></span></code></pre> Post on Sara Soueidan – Blog - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/_template/ 2025-08-18T08:41:01.000Z Abbreviations can be problematic - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/abbreviations-can-be-problematic/ 2025-08-18T08:41:01.000Z <blockquote> <p>If the acronym is used once, simply using the words is usually the right approach. [
] When an acronym is used multiple times, though, it’s likely it’s being used for practical reasons rather than tone of voice. Reading can be clunky if the words are written in full each time, so all we have to do is define it the first time it’s used on each page; from there on in it can be used freely.</p> </blockquote> <p>After I tweeted this article on Twitter, <a href="https://twitter.com/pustelto/status/1549305652379533312?s=20&amp;t=U5sk7WXWnU-Aa2h0Gxv2tA">Tomas shared</a> <a href="https://gist.github.com/klaaspieter/12cd68f54bb71a3940eae5cdd4ea1764">a letter by Elon Musk to SpaceX engineers</a> about the same topic.</p> <blockquote> <p>Excessive use of made up acronyms is a significant impediment to communication and keeping communication good as we grow is incredibly important. Individually, a few acronyms here and there may not seem so bad, but if a thousand people are making these up, over time the result will be a huge glossary that we have to issue to new employees. No one can actually remember all these acronyms and people don’t want to seem dumb in a meeting, so they just sit there in ignorance. This is particularly tough on new employees.</p> </blockquote> <p>Just use the words.</p> Accessible design systems - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/accessible-design-systems/ 2025-08-18T08:41:01.000Z <blockquote> <p>A design system is a library of styles, components, and patterns used by product teams to consistently and efficiently launch new pages and features. A good system has accessibility embedded throughout and includes documentation, guidelines and implementation notes for accessibility.</p> </blockquote> <p>Accessibility in design systems goes beyond code:</p> <blockquote> <p>Design systems vary, but an accessible design system can include style guides, components, patterns, and accessibility documentation.</p> </blockquote> Best practices for using third party embeds - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/best-practices-for-using-third-party-embeds/ 2025-08-18T08:41:01.000Z Beyond WCAG: Losing Spoons Online - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/beyond-wcag-losing-spoons-online/ 2025-08-18T08:41:01.000Z <blockquote> <p>I’d like to share some of the things online that drain my spoons to help you go beyond WCAG today. For the sake of this scenario, I’ll include how many spoons I can expect to lose when I encounter these blockers. Let’s say that I start my day with twenty spoons.</p> </blockquote> <p>I haven’t been able to get this article out of my head since I read it. Learning about people’s experiences fundamentally changes how you think about creating for the Web. In the end, you either care; or you don’t.</p> Body margin 8px - The origin story for a style no one wants - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/body-margin-8px/ 2025-08-18T08:41:01.000Z <blockquote> <p>All browsers add an 8px margin on the body element – it’s part of the w3c-recommended default stylesheet which browsers generally use as a starting point for their own ‘user agent’ styles. But why 8px? Where does that come from?</p> </blockquote> <p>I really enjoyed reading Mia’s article. The article starts by explaining the difference between initial values in CSS and browser default styles. I had an ah-ha moment that’s going to finally help me remember the difference between the <code>initial</code> and <code>revert</code> values for good!</p> Avoiding layout shift by putting the CSS in charge - HTTP 203 - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/flex-vs-grid-performance/ 2025-08-18T08:41:01.000Z <p>I had never considered how CSS Grid and Flexbox compare from a performance standpoint. This is insightful.</p> The ‘Form’ Element Created the Modern Web. Was It a Big Mistake? - Sara Soueidan – Blog https://www.sarasoueidan.com/content/links/forms/ 2025-08-18T08:41:01.000Z <blockquote> <p>the <code>&lt;form&gt;</code> element was a pivot point for the entire technology industry. It is what changed the web from a read-only medium for physics papers into a read-write medium for anything. But lately I’m not so sure I think that was a good idea. [
] What forms enable are transactions. Transactions of all kinds—commercial or social—can be consolidated into platforms, and platforms are where you find your margins. And margins are what yield your fortune, and that’s how you get power.</p> </blockquote>