<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Design on Smashing Magazine — For Web Designers And Developers</title><link>https://www.smashingmagazine.com/category/design/index.xml</link><description>Recent content in Design on Smashing Magazine — For Web Designers And Developers</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 09 Feb 2026 03:03:08 +0000</lastBuildDate><item><author>Vitaly Friedman</author><title>Combobox vs. Multiselect vs. Listbox: How To Choose The Right One</title><link>https://www.smashingmagazine.com/2026/02/combobox-vs-multiselect-vs-listbox/</link><pubDate>Tue, 03 Feb 2026 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2026/02/combobox-vs-multiselect-vs-listbox/</guid><description>Combobox vs. Multi-Select vs. Listbox vs. Dual Listbox? How they are different, what purpose they serve, and how to choose the right one. Brought to you by &lt;a href="https://ai-design-patterns.com">Design Patterns For AI Interfaces&lt;/a>, &lt;strong>friendly video courses on UX&lt;/strong> and design patterns by Vitaly.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2026/02/combobox-vs-multiselect-vs-listbox/" />
              <title>Combobox vs. Multiselect vs. Listbox: How To Choose The Right One</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Combobox vs. Multiselect vs. Listbox: How To Choose The Right One</h1>
                  
                    
                    <address>Vitaly Friedman</address>
                  
                  <time datetime="2026-02-03T10:00:00&#43;00:00" class="op-published">2026-02-03T10:00:00+00:00</time>
                  <time datetime="2026-02-03T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>So what’s the difference between combobox, multiselect, listbox, and dropdown? While all these UI components might appear similar, they serve different purposes. The choice often comes down to the <strong>number of available options</strong> and their visibility.</p>

<p>Let’s see how they differ, <strong>what purpose they serve</strong>, and how to choose the right one &mdash; avoiding misunderstandings and wrong expectations along the way.</p>














<figure class="
  
  
  ">
  
    <a href="https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="858"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg"
			
			sizes="100vw"
			alt="A comparison of UI elements: Listbox, Combobox, Multiselect, and Dual Listbox, showcasing different selection functionalities."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      And the confusion begins: Listbox, Combobox, Multiselect, Dual Listbox. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/1-combobox-vs-multiselect-vs-listbox.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="not-all-list-patterns-are-the-same">Not All List Patterns Are The Same</h2>

<p>All the UI components highlighted above have exactly one thing in common: they support users’ interactions with lists. However, they do so slightly differently.</p>

<p>Let’s take a look at each, one by one:</p>

<ul>
<li><strong>Dropdown</strong> → list is hidden until it’s triggered.</li>
<li><strong>Combobox</strong> → type to filter + select 1 option.</li>
<li><strong>Multiselect</strong> → type to filter + select many options.</li>
<li><strong>Listbox</strong> → all list options visible by default (+ scroll).</li>
<li><strong>Dual listbox</strong> → move items between 2 listboxes.</li>
</ul>














<figure class="
  
  
  ">
  
    <a href="https://watson.docplanner.design/latest/watson-web/components/combobox/usage-guidelines-L68K6G51">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="825"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg"
			
			sizes="100vw"
			alt="A text input field with a dropdown list"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Watson design system with grouping inside of its <a href='https://watson.docplanner.design/latest/watson-web/components/combobox/usage-guidelines-L68K6G51'>combobox pattern</a>. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/2-watson-design-system.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>In other words, <em>Combobox</em> combines a text input field with a dropdown list, so users can <strong>type to filter</strong> and select a single option. With <em>Multiselect</em>, users can select many options (often displayed as pills or chips).</p>

<p><em>Listboxes</em> display <strong>all list options visible</strong> by default, often with scrolling. It’s helpful when users need to see all available choices immediately. <em>Dual listbox</em> (also called <em>transfer list</em>) is a variation of a listbox that allows users to <strong>move items between two listboxes</strong> (left ↔ right), typically for bulk selection.</p>

<h2 id="never-hide-frequently-used-options">Never Hide Frequently Used Options</h2>

<p>As mentioned above, the choice of the right UI component depends on <strong>2 factors</strong>: how many list options are available, and if all these options need to be visible by default. All lists could have tree structures, nesting, and group selection, too.</p>














<figure class="
  
  
  ">
  
    <a href="https://www.mongodb.design/component/combobox/design-docs">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="776"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg"
			
			sizes="100vw"
			alt="A dropdown menu showing product selection. Compass is selected, and Atlas is selected with two sub-options: Vector Search and Atlas CLI."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.mongodb.design/component/combobox/live-example'>MongoDB design system</a> with nested filters and chips. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/3-nongodb-design-system.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>There is one principle that I’ve been following for years for any UI component: <strong>never hide frequently used options</strong>. If users rely on a particular selection frequently, there is very little value in hiding it from them.</p>

<p>We could either make it <strong>pre-selected</strong>, or (if there are only 2–3 frequently used options) show them as <a href="https://smart-interface-design-patterns.com/articles/badges-chips-tags-pills/"><strong>chips or buttons</strong></a>, and then show the rest of the list on interaction. In general, it’s a good idea to always display popular options &mdash; even if it might clutter the UI.</p>

<h2 id="how-to-choose-which">How To Choose Which?</h2>

<p>Not every list needs a complex selection method. For lists with <strong>fewer than 5 items</strong>, simple radio buttons or checkboxes usually work best. But if users need to select from a <strong>large list</strong> of options (e.g., 200+ items), combobox + multiselect are helpful because of the faster filtering (e.g., country selection).</p>














<figure class="
  
  
  ">
  
    <a href="https://www.nngroup.com/articles/listbox-dropdown/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="722"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg"
			
			sizes="100vw"
			alt="Matrix of options for multiselect and listboxes."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      A <a href='https://www.nngroup.com/articles/listbox-dropdown/'>matrix of options</a>, broken down by single- or multi-selection and static or scrollable view. By Anna Kaley, from NN/g. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/4-matrix-options-multiselect-listboxes.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p><strong>Listboxes</strong> are helpful when people need to access <strong>many options at once</strong>, especially if they need to choose many options from that list as well. They could be helpful for frequently used filters.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://v5.mantine.dev/core/transfer-list/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="468"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png"
			
			sizes="100vw"
			alt="Dual list box used to transfer items from one place to another."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Dual listbox in action: it can be very helpful when assigning tasks or permissions. That’s why it’s “Transfer List”. Example from <a href='https://v5.mantine.dev/core/transfer-list/'>Mantine</a>. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/5-dual-list-box.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p><strong>Dual listbox</strong> is often overlooked and ignored. But it can be very helpful for complex tasks, e..g bulk selection, or assigning roles, tasks, responsibilities. It’s the only UI component that allows users to review their full selection list side-by-side with the source list before committing (also called <em>“Transfer list”</em>).</p>

<p>In fact, dual listbox is often faster, more accurate, and more accessible than <a href="https://smart-interface-design-patterns.com/articles/drag-and-drop-ux/">drag-and-drop</a>.</p>

<h2 id="usability-considerations">Usability Considerations</h2>

<p>One important note to keep in mind is that all list types need to support <strong>keyboard navigation</strong> (e.g., ↑/↓ arrow keys) for accessibility. Some people will almost always rely uponthe  keyboard to select options once they start typing.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://watson.docplanner.design/latest/watson-web/components/combobox/usage-guidelines-L68K6G51">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="555"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png"
			
			sizes="100vw"
			alt="Keyboard navigation is often in use with any type of lists."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Keyboard navigation is often in use with any kind of lists. Example: <a href='https://watson.docplanner.design/latest/watson-web/components/combobox/usage-guidelines-L68K6G51'>Watson</a>. (<a href='https://files.smashing.media/articles/combobox-vs-multiselect-vs-listbox/7-keyboard-navigation.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Beyond that:</p>

<ul>
<li>For lists with <strong>7+ options</strong>, consider adding “Select All” and “Clear All” functionalities to streamline user interaction.</li>
<li>For lengthy lists with a combobox, <strong>expose all options</strong> to users on click/tap, as otherwise they might never be seen,</li>
<li>Most important, <strong>don’t display non-interactive elements as buttons</strong> to avoid confusion &mdash; and don&rsquo;t display interactive elements as static labels.</li>
</ul>

<h2 id="wrapping-up-not-everything-is-a-dropdown">Wrapping Up: Not Everything Is A Dropdown</h2>

<p>Names matter. A <strong>vertical list of options</strong> is typically described as a “dropdown” &mdash; but often it’s a bit too generic to be meaningful. <em>“Dropdown”</em> hints that the list is hidden by default. <em>“Multiselect”</em> implies multi-selection (checkbox) within a list. <em>“Combobox”</em> implies text input. And “Listbox” is simply a list of selectable items, visible at all times.</p>

<p>The goal isn’t to be consistent with the definitions above for the sake of it. But rather to <strong>align intentions</strong> &mdash; speak the same language when deciding on, designing, building, and then using these UI components.</p>

<p>It <strong>should work for everyone</strong> &mdash; designers, engineers, and end users &mdash; as long as static labels don’t look like interactive buttons, and radio buttons don’t act like checkboxes.</p>

<h2 id="meet-design-patterns-for-ai-interfaces">Meet “Design Patterns For AI Interfaces”</h2>

<p>Meet <a href="https://ai-design-patterns.com/"><strong>Design Patterns For AI Interfaces</strong></a>, Vitaly’s new <strong>video course</strong> with practical examples from real-life products &mdash; with a <a href="https://smashingconf.com/online-workshops/workshops/ai-interfaces-vitaly-friedman/">live UX training</a> happening soon. <a href="https://www.youtube.com/watch?v=jhZ3el3n-u0">Jump to a free preview</a>.</p>

<p><figure class="article__image" style="margin-bottom: 0"><a href="https://ai-design-patterns.com/"><img style="border-radius:11px" loading="lazy" decoding="async" fetchpriority="low" width="800" height="414" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 400w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 800w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 1200w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 1600w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 2000w" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png" sizes="100vw" alt="Design Patterns For AI Interfaces promo picture"></a><figcaption class="op-vertical-bottom">Meet <a href="https://ai-design-patterns.com/">Design Patterns For AI Interfaces</a>, Vitaly’s video course on interface design &amp; UX.</figcaption></figure>
<div class="book-cta__inverted"><div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"><nav class="content-tabs content-tabs--books"><ul><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">
Video + UX Training</button></a></li><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">Video only</button></a></li></ul></nav><div class="book-cta__col book-cta__hardcover content-tab--content"><h3 class="book-cta__title"><span>Video + UX Training</span></h3><span class="book-cta__price"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>450<span class="sup">.00</span></span></span> <span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>799<span class="sup">.00</span></span></span></span></span>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3476562?price_id=4401578" class="btn btn--full btn--medium btn--text-shadow">
Get Video + UX Training<div></div></a><p class="book-cta__desc">30 video lessons (10h) + <a href="https://smashingconf.com/online-workshops/workshops/ai-interfaces-vitaly-friedman/">Live UX Training</a>.<br>100 days money-back-guarantee.</p></div><div class="book-cta__col book-cta__ebook content-tab--content"><h3 class="book-cta__title"><span>Video only</span></h3><div data-audience="anonymous free supporter" data-remove="true"><span class="book-cta__price" data-handler="PriceTag"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>275<span class="sup">.00</span></span></span><span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>395<span class="sup">.00</span></span></span></span></div>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3476562?price_id=4397456" class="btn btn--full btn--medium btn--text-shadow">
Get the video course<div></div></a><p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true">30 video lessons (10h). Updated yearly.<br>Also available as a <a href="https://smart-interface-design-patterns.thinkific.com/enroll/3570306?price_id=4503439">UX Bundle with 3 video courses.</a></p></div><span></span></div></div></p>

<h2 id="useful-resources">Useful Resources</h2>

<ul>
<li><a href="https://smart-interface-design-patterns.com/articles/autocomplete-ux/">Autocomplete: UX Guidelines</a>, by Vitaly Friedman</li>
<li><a href="https://playbook.ebay.com/design-system/components/combobox">Combobox</a>, by eBay 👍</li>
<li><a href="https://eui.elastic.co/docs/components/forms/selection/combo-box/">Combobox</a>, by Elastic</li>
<li><a href="https://designsystem.elisa.fi/9b207b2c3/p/082dd3-combobox">Combobox</a>, by Elisa</li>
<li><a href="https://www.mongodb.design/component/combobox/live-example">Combobox</a>, by MongoDB 👍</li>
<li><a href="https://design.visa.com/components/combobox/">Combobox</a>, by Visa 👍</li>
<li><a href="https://watson.docplanner.design/latest/watson-web/components/combobox/usage-guidelines-L68K6G51">Combobox</a>, by Watson (Docplanner)</li>
<li><a href="https://doc.wikimedia.org/codex/latest/components/demos/combobox.html">Combobox</a>, by Wikimedia</li>
<li><a href="https://garden.zendesk.com/components/combobox">Combobox</a>, by Zendesk</li>
<li><a href="https://www.mongodb.design/component/combobox/design-docs">Multiselect (MongoDB Combobox Design Docs)</a>, by MongoDB 👍</li>
<li><a href="https://doc.wikimedia.org/codex/latest/components/demos/multiselect-lookup.html">Multiselect Lookup</a>, by Wikimedia</li>
<li><a href="https://vaadin.com/docs/latest/components/multi-select-combo-box">Multi-select Combo Box</a>, by Vaadin</li>
<li><a href="https://design.visa.com/components/multiselect/">Multiselect</a>, by Visa</li>
<li><a href="https://ant.design/components/transfer">Transfer (Listbox example)</a>, by Ant Design</li>
<li><a href="https://hopper.workleap.design/components/Listbox">Listbox</a>, by Hopper</li>
<li><a href="https://vaadin.com/docs/latest/components/list-box">List Box</a>, by Vaadin</li>
<li><a href="https://design.visa.com/components/listbox/">Listbox</a>, by Visa</li>
<li><a href="https://www.patternfly.org/components/dual-list-selector">Dual List Selector</a>, by Red Hat (PatternFly)</li>
<li><a href="https://www.lightningdesignsystem.com/2e1ef8501/p/763763-dual-listbox">Dual Listbox</a>, by Salesforce (Lightning Design System)</li>
<li><a href="https://v5.mantine.dev/core/transfer-list/">Transfer List</a>, by Mantine</li>
<li><a href="https://dashlite.net/demo1/components/misc/dual-listbox.html">Dual Listbox</a>, by Dashlite</li>
<li><a href="https://smart-interface-design-patterns.com/articles/badges-chips-tags-pills/">Badges vs. Pills vs. Chips vs. Tags</a>, by Vitaly Friedman</li>
<li><a href="https://www.nngroup.com/articles/listbox-dropdown/">Listboxes vs. Dropdown Lists</a>, by Anna Kaley (NN/g)</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Victor Yocco</author><title>Beyond Generative: The Rise Of Agentic AI And User-Centric Design</title><link>https://www.smashingmagazine.com/2026/01/beyond-generative-rise-agentic-ai-user-centric-design/</link><pubDate>Thu, 22 Jan 2026 13:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2026/01/beyond-generative-rise-agentic-ai-user-centric-design/</guid><description>Developing effective agentic AI requires a new research playbook. When systems plan, decide, and act on our behalf, UX moves beyond usability testing into the realm of trust, consent, and accountability. Victor Yocco outlines the research methods needed to design agentic AI systems responsibly.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2026/01/beyond-generative-rise-agentic-ai-user-centric-design/" />
              <title>Beyond Generative: The Rise Of Agentic AI And User-Centric Design</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Beyond Generative: The Rise Of Agentic AI And User-Centric Design</h1>
                  
                    
                    <address>Victor Yocco</address>
                  
                  <time datetime="2026-01-22T13:00:00&#43;00:00" class="op-published">2026-01-22T13:00:00+00:00</time>
                  <time datetime="2026-01-22T13:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>Agentic AI stands ready to transform customer experience and operational efficiency, necessitating a new strategic approach from leadership. This evolution in artificial intelligence empowers systems to <strong>plan</strong>, <strong>execute</strong>, and <strong>persist</strong> in tasks, moving beyond simple recommendations to proactive action. For UX teams, product managers, and executives, understanding this shift is crucial for unlocking opportunities in innovation, streamlining workflows, and redefining how technology serves people.</p>

<p>It’s easy to confuse <strong>Agentic AI</strong> with Robotic Process Automation (RPA), which is technology that focuses on rules-based tasks performed on computers. The distinction lies in rigidity versus reasoning. RPA is excellent at following a strict script: if X happens, do Y. It mimics human hands. Agentic AI mimics human reasoning. It does not follow a linear script; it <strong>creates</strong> one.</p>

<p>Consider a recruiting workflow. An RPA bot can scan a resume and upload it to a database. It performs a repetitive task perfectly. An Agentic system looks at the resume, notices the candidate lists a specific certification, cross-references that with a new client requirement, and decides to draft a personalized outreach email highlighting that match. RPA executes a predefined plan; Agentic AI formulates the plan based on a goal. This autonomy separates agents from the predictive tools we have used for the last decade.</p>

<p>Another example is managing meeting conflicts. A predictive model integrated into your calendar might analyze your meeting schedule and the schedules of your colleagues. It could then suggest potential conflicts, such as two important meetings scheduled at the same time, or a meeting scheduled when a key participant is on vacation. It provides you with information and flags potential issues, but you are responsible for taking action.</p>

<p>An agentic AI, in the same scenario, would go beyond just suggesting conflicts to avoid. Upon identifying a conflict with a key participant, the agent could act by:</p>

<ul>
<li>Checking the availability of all necessary participants.</li>
<li>Identifying alternative time slots that work for everyone.</li>
<li>Sending out proposed new meeting invitations to all attendees.</li>
<li>If the conflict is with an external participant, the agent could draft and send an email explaining the need to reschedule and offering alternative times.</li>
<li>Updating your calendar and the calendars of your colleagues with the new meeting details once confirmed.</li>
</ul>

<p>This agentic AI understands the goal (resolving the meeting conflict), plans the steps (checking availability, finding alternatives, sending invites), executes those steps, and persists until the conflict is resolved, all with minimal direct user intervention. This demonstrates the “agentic” difference: the system takes <strong>proactive steps</strong> for the user, rather than just providing information to the user.</p>

<p>Agentic AI systems understand a goal, plan a series of steps to achieve it, execute those steps, and even adapt if things go wrong. Think of it like a <strong>proactive digital assistant</strong>. The underlying technology often combines large language models (LLMs) for understanding and reasoning, with planning algorithms that break down complex tasks into manageable actions. These agents can interact with various tools, APIs, and even other AI models to accomplish their objectives, and critically, they can maintain a persistent state, meaning they remember previous actions and continue working towards a goal over time. This makes them fundamentally different from typical generative AI, which usually completes a single request and then resets.</p>

<h2 id="a-simple-taxonomy-of-agentic-behaviors">A Simple Taxonomy of Agentic Behaviors</h2>

<p>We can categorize agent behavior into four distinct modes of autonomy. While these often look like a progression, they function as independent operating modes. A user might trust an agent to act autonomously for scheduling, but keep it in “suggestion mode” for financial transactions.</p>

<p>We derived these levels by adapting industry standards for autonomous vehicles (<a href="https://www.sae.org/news/blog/sae-levels-driving-automation-clarity-refinements">SAE levels</a>) to digital user experience contexts.</p>

<h3 id="observe-and-suggest">Observe-and-Suggest</h3>

<p>The agent functions as a monitor. It analyzes data streams and flags anomalies or opportunities, but takes zero action.</p>

<p><strong>Differentiation</strong><br />
Unlike the next level, the agent generates no complex plan. It points to a problem.</p>

<p><strong>Example</strong><br />
A DevOps agent notices a server CPU spike and alerts the on-call engineer. It does not know how or attempt to fix it, but it knows something is wrong.</p>

<p><strong>Implications for design and oversight</strong><br />
At this level, design and oversight should prioritize clear, non-intrusive notifications and a well-defined process for users to act on suggestions. The focus is on empowering the user with timely and relevant information without taking control. UX practitioners should focus on making suggestions clear and easy to understand, while product managers need to ensure the system provides value without overwhelming the user.</p>

<h3 id="plan-and-propose">Plan-and-Propose</h3>

<p>The agent identifies a goal and generates a multi-step strategy to achieve it. It presents the full plan for human review.</p>

<p><strong>Differentiation</strong><br />
The agent acts as a strategist. It does not execute; it waits for approval on the entire approach.</p>

<p><strong>Example</strong><br />
The same DevOps agent notices the CPU spike, analyzes the logs, and proposes a remediation plan:</p>

<ol>
<li>Spin up two extra instances.</li>
<li>Restart the load balancer.</li>
<li>Archive old logs.</li>
</ol>

<p>The human reviews the logic and clicks “Approve Plan”.</p>

<p><strong>Implications for design and oversight</strong><br />
For agents that plan and propose, design must ensure the proposed plans are easily understandable and that users have intuitive ways to modify or reject them. Oversight is crucial in monitoring the quality of proposals and the agent’s planning logic. UX practitioners should design clear visualizations of the proposed plans, and product managers must establish clear review and approval workflows.</p>

<h3 id="act-with-confirmation">Act-with-Confirmation</h3>

<p>The agent completes all preparation work and places the final action in a staged state. It effectively holds the door open, waiting for a nod.</p>

<p><strong>Differentiation</strong><br />
This differs from “Plan-and-Propose” because the work is already done and staged. It reduces friction. The user confirms the outcome, not the strategy.</p>

<p><strong>Example</strong><br />
A recruiting agent drafts five interview invitations, finds open times on calendars, and creates the calendar events. It presents a “Send All” button. The user provides the final authorization to trigger the external action.</p>

<p><strong>Implications for design and oversight</strong><br />
When agents act with confirmation, the design should provide transparent and concise summaries of the intended action, clearly outlining potential consequences. Oversight needs to verify that the confirmation process is robust and that users are not being asked to blindly approve actions. UX practitioners should design confirmation prompts that are clear and provide all necessary information, and product managers should prioritize a robust audit trail for all confirmed actions.</p>

<h3 id="act-autonomously">Act-Autonomously</h3>

<p>The agent executes tasks independently within defined boundaries.</p>

<p><strong>Differentiation</strong><br />
The user reviews the history of actions, not the actions themselves.</p>

<p><strong>Example</strong><br />
The recruiting agent sees a conflict, moves the interview to a backup slot, updates the candidate, and notifies the hiring manager. The human only sees a notification: Interview rescheduled to Tuesday.</p>

<p><strong>Implications for design and oversight</strong><br />
For autonomous agents, the design needs to establish clear pre-approved boundaries and provide robust monitoring tools. Oversight requires continuous evaluation of the agent’s performance within these boundaries, a critical need for robust logging, clear override mechanisms, and user-defined kill switches to maintain user control and trust. UX practitioners should focus on designing effective dashboards for monitoring autonomous agent behavior, and product managers must ensure clear governance and ethical guidelines are in place.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="640"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png"
			
			sizes="100vw"
			alt="The Agentic Autonomy Matrix"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <strong>Figure 1</strong>: The Agentic Autonomy Matrix. This framework maps four distinct operating modes by correlating the level of agent initiative against the required amount of human intervention. (<a href='https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/1-agentic-autonomy-matrix.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Let’s look at a real-world application in HR technology to see these modes in action. Consider an “Interview Coordination Agent” designed to handle the logistics of hiring.</p>

<ul>
<li><strong>In Suggest Mode</strong><br />
The agent notices an interviewer is double-booked. It highlights the conflict on the recruiter’s dashboard: <em>“Warning: Sarah is double-booked for the 2 PM interview.”</em></li>
<li><strong>In Plan Mode</strong><br />
The agent analyzes Sarah’s calendar and the candidate’s availability. It presents a solution: <em>“I recommend moving the interview to Thursday at 10 AM. This requires moving Sarah’s 1:1 with her manager.”</em> The recruiter reviews this logic.</li>
<li><strong>In Confirmation Mode</strong><br />
The agent drafts the emails to the candidate and the manager. It populates the calendar invites. The recruiter sees a summary: <em>“Ready to reschedule to Thursday. Send updates?”</em> The recruiter clicks <em>“Confirm.”</em></li>
<li><strong>In Autonomous Mode</strong><br />
The agent handles the conflict instantly. It respects a pre-set rule: <em>“Always prioritize candidate interviews over internal 1:1s.”</em> It moves the meeting and sends the notifications. The recruiter sees a log entry: <em>“Resolved schedule conflict for Candidate B.”</em></li>
</ul>

<h2 id="research-primer-what-to-research-and-how">Research Primer: What To Research And How</h2>

<p>Developing effective agentic AI demands a distinct research approach compared to traditional software or even generative AI. The autonomous nature of AI agents, their ability to make decisions, and their potential for proactive action necessitate specialized methodologies for understanding user expectations, mapping complex agent behaviors, and anticipating potential failures. The following research primer outlines key methods to measure and evaluate these unique aspects of agentic AI.</p>

<h3 id="mental-model-interviews">Mental-Model Interviews</h3>

<p>These interviews uncover users’ preconceived notions about how an AI agent should behave. Instead of simply asking what users <em>want</em>, the focus is on understanding their internal models of the agent’s capabilities and limitations. We should avoid using the word “agent” with participants. It carries sci-fi baggage or is a term too easily confused with a human agent offering support or services. Instead, frame the discussion around “assistants” or “the system.”</p>

<p>We need to uncover where users draw the line between helpful automation and intrusive control.</p>

<ul>
<li><strong>Method:</strong> Ask users to describe, draw, or narrate their expected interactions with the agent in various hypothetical scenarios.</li>
<li><strong>Key Probes (reflecting a variety of industries):</strong>

<ul>
<li>To understand the boundaries of desired automation and potential anxieties around over-automation, ask:

<ul>
<li>If your flight is canceled, what would you want the system to do automatically? What would worry you if it did that without your explicit instruction?</li>
</ul></li>
<li>To explore the user’s understanding of the agent’s internal processes and necessary communication, ask:

<ul>
<li>Imagine a digital assistant is managing your smart home. If a package is delivered, what steps do you imagine it takes, and what information would you expect to receive?</li>
</ul></li>
<li>To uncover expectations around control and consent within a multi-step process, ask:

<ul>
<li>If you ask your digital assistant to schedule a meeting, what steps do you envision it taking? At what points would you want to be consulted or given choices?</li>
</ul></li>
</ul></li>
<li><strong>Benefits of the method:</strong> Reveals implicit assumptions, highlights areas where the agent’s planned behavior might diverge from user expectations, and informs the design of appropriate controls and feedback mechanisms.</li>
</ul>

<h3 id="agent-journey-mapping">Agent Journey Mapping:</h3>

<p>Similar to traditional user journey mapping, agent journey mapping specifically focuses on the anticipated actions and decision points of the AI agent itself, alongside the user’s interaction. This helps to proactively identify potential pitfalls.</p>

<ul>
<li><strong>Method:</strong> Create a visual map that outlines the various stages of an agent’s operation, from initiation to completion, including all potential actions, decisions, and interactions with external systems or users.</li>
<li><strong>Key Elements to Map:</strong>

<ul>
<li><strong>Agent Actions:</strong> What specific tasks or decisions does the agent perform?</li>
<li><strong>Information Inputs/Outputs:</strong> What data does the agent need, and what information does it generate or communicate?</li>
<li><strong>Decision Points:</strong> Where does the agent make choices, and what are the criteria for those choices?</li>
<li><strong>User Interaction Points:</strong> Where does the user provide input, review, or approve actions?</li>
<li><strong>Points of Failure:</strong> Crucially, identify specific instances where the agent could misinterpret instructions, make an incorrect decision, or interact with the wrong entity.

<ul>
<li><strong>Examples:</strong> Incorrect recipient (e.g., sending sensitive information to the wrong person), overdraft (e.g., an automated payment exceeding available funds), misinterpretation of intent (e.g., booking a flight for the wrong date due to ambiguous language).</li>
</ul></li>
<li><strong>Recovery Paths:</strong> How can the agent or user recover from these failures? What mechanisms are in place for correction or intervention?</li>
</ul></li>
<li><strong>Benefits of the method:</strong> Provides a holistic view of the agent’s operational flow, uncovers hidden dependencies, and allows for the proactive design of safeguards, error handling, and user intervention points to prevent or mitigate negative outcomes.</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="437"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg"
			
			sizes="100vw"
			alt="Agent Journey Map"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <strong>Figure 2</strong>: Agent Journey Map. Mapping the Agent Logic distinct from the System helps identify where the reasoning, not just the code, might fail. (<a href='https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/2-agent-journey-map.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<h3 id="simulated-misbehavior-testing">Simulated Misbehavior Testing:</h3>

<p>This approach is designed to stress-test the system and observe user reactions when the AI agent <em>fails</em> or deviates from expectations. It’s about understanding trust repair and emotional responses in adverse situations.</p>

<ul>
<li><strong>Method:</strong> In controlled lab studies, deliberately introduce scenarios where the agent makes a mistake, misinterprets a command, or behaves unexpectedly.</li>
<li><strong>Types of “Misbehavior” to Simulate:</strong>

<ul>
<li><strong>Command Misinterpretation:</strong> The agent performs an action slightly different from what the user intended (e.g., ordering two items instead of one).</li>
<li><strong>Information Overload/Underload:</strong> The agent provides too much irrelevant information or not enough critical details.</li>
<li><strong>Unsolicited Action:</strong> The agent takes an action the user explicitly did not want or expect (e.g., buying stock without approval).</li>
<li><strong>System Failure:</strong> The agent crashes, becomes unresponsive, or provides an error message.</li>
<li><strong>Ethical Dilemmas:</strong> The agent makes a decision with ethical implications (e.g., prioritizing one task over another based on an unforeseen metric).</li>
</ul></li>
<li><strong>Observation Focus:</strong>

<ul>
<li><strong>User Reactions:</strong> How do users react emotionally (frustration, anger, confusion, loss of trust)?</li>
<li><strong>Recovery Attempts:</strong> What steps do users take to correct the agent’s behavior or undo its actions?</li>
<li><strong>Trust Repair Mechanisms:</strong> Do the system’s built-in recovery or feedback mechanisms help restore trust? How do users want to be informed about errors?</li>
<li><strong>Mental Model Shift:</strong> Does the misbehavior alter the user’s understanding of the agent’s capabilities or limitations?</li>
</ul></li>
<li><strong>Benefits of the method:</strong> Crucial for identifying design gaps related to error recovery, feedback, and user control. It provides insights into how resilient users are to agent failures and what is needed to maintain or rebuild trust, leading to more robust and forgiving agentic systems.</li>
</ul>

<p>By integrating these research methodologies, UX practitioners can move beyond simply making agentic systems <em>usable</em> to making them <em>trusted</em>, <em>controllable</em>, and <em>accountable</em>, fostering a positive and productive relationship between users and their AI agents. Note that these aren’t the only methods relevant to exploring agentic AI effectively. Many other methods exist, but these are most accessible to practitioners in the near term. I’ve previously covered the Wizard of Oz method, a slightly more advanced method of concept testing, which is also a valuable tool for exploring agentic AI concepts.</p>

<h2 id="ethical-considerations-in-research-methodology">Ethical Considerations In Research Methodology</h2>

<p>When researching agentic AI, particularly when simulating misbehavior or errors, ethical considerations are key to take into account. There are many publications focusing on ethical UX research, including an <a href="https://www.smashingmagazine.com/2020/12/ethical-considerations-ux-research/">article I wrote for Smashing Magazine</a>, <a href="https://www.uxdesigninstitute.com/blog/what-are-user-research-ethics/">these guidelines</a> from the UX Design Institute, and this page from the <a href="https://www.inclusivedesigntoolkit.com/ethics/">Inclusive Design Toolkit</a>.</p>

<h2 id="key-metrics-for-agentic-ai">Key Metrics For Agentic AI</h2>

<p>You’ll need a comprehensive set of key metrics to effectively assess the performance and reliability of agentic AI systems. These metrics provide insights into user trust, system accuracy, and the overall user experience. By tracking these indicators, developers and designers can identify areas for improvement and ensure that AI agents operate safely and efficiently.</p>

<p><strong>1. Intervention Rate</strong><br />
For autonomous agents, we measure success by silence. If an agent executes a task and the user does not intervene or reverse the action within a set window (e.g., 24 hours), we count that as acceptance. We track the Intervention Rate: how often does a human jump in to stop or correct the agent? A high intervention rate signals a misalignment in trust or logic.</p>

<p><strong>2. Frequency of Unintended Actions per 1,000 Tasks</strong><br />
This critical metric quantifies the number of actions performed by the AI agent that were not desired or expected by the user, normalized per 1,000 completed tasks. A low frequency of unintended actions signifies a well-aligned AI that accurately interprets user intent and operates within defined boundaries. This metric is closely tied to the AI’s understanding of context, its ability to disambiguate commands, and the robustness of its safety protocols.</p>

<p><strong>3. Rollback or Undo Rates</strong><br />
This metric tracks how often users need to reverse or undo an action performed by the AI. High rollback rates suggest that the AI is making frequent errors, misinterpreting instructions, or acting in ways that are not aligned with user expectations. Analyzing the reasons behind these rollbacks can provide valuable feedback for improving the AI’s algorithms, understanding of user preferences, and its ability to predict desirable outcomes.</p>

<p>To understand why, you must implement a microsurvey on the undo action. For example, when a user reverses a scheduling change, a simple prompt can ask: <em>“Wrong time? Wrong person? Or did you just want to do it yourself?”</em> Allowing the user to click on the option that best corresponds to their reasoning.</p>

<p><strong>4. Time to Resolution After an Error</strong><br />
This metric measures the duration it takes for a user to correct an error made by the AI or for the AI system itself to recover from an erroneous state. A short time to resolution indicates an efficient and user-friendly error recovery process, which can mitigate user frustration and maintain productivity. This includes the ease of identifying the error, the accessibility of undo or correction mechanisms, and the clarity of error messages provided by the AI.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="437"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg"
			
			sizes="100vw"
			alt="A Trust &amp; Accountability Dashboard"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <strong>Figure 3</strong>: A Trust & Accountability Dashboard. Note the focus on “Rollback Reasons”. This qualitative data is vital for tuning the agent’s logic. (<a href='https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/3-trust-accountability-dashboard.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Collecting these metrics requires instrumenting your system to track Agent Action IDs. Every distinct action the agent takes, such as proposing a schedule or booking a flight, must generate a unique ID that persists in the logs. To measure the Intervention Rate, we do not look for an immediate user reaction. We look for the absence of a counter-action within a defined window. If an Action ID is generated at 9:00 AM and no human user modifies or reverts that specific ID by 9:00 AM the next day, the system logically tags it as Accepted. This allows us to quantify success based on user silence rather than active confirmation.</p>

<p>For Rollback Rates, raw counts are insufficient because they lack context. To capture the underlying reason, you must implement intercept logic on your application’s Undo or Revert functions. When a user reverses an agent-initiated action, trigger a lightweight microsurvey. This can be a simple three-option modal asking the user to categorize the error as factually incorrect, lacking context, or a simple preference to handle the task manually. This combines quantitative telemetry with qualitative insight. It enables engineering teams to distinguish between a broken algorithm and a user preference mismatch.</p>

<p>These metrics, when tracked consistently and analyzed holistically, provide a robust framework for evaluating the performance of agentic AI systems, allowing for continuous improvement in control, consent, and accountability.</p>

<h2 id="designing-against-deception">Designing Against Deception</h2>

<p>As agents become increasingly capable, we face a new risk: <strong>Agentic Sludge</strong>. Traditional sludge creates friction that makes it hard to cancel a subscription or delete an account. Agentic sludge acts in reverse. It removes friction to a fault, making it too easy for a user to agree to an action that benefits the business rather than their own interests.</p>

<p>Consider an agent assisting with travel booking. Without clear guardrails, the system might prioritize a partner airline or a higher-margin hotel. It presents this choice as the optimal path. The user, trusting the system’s authority, accepts the recommendation without scrutiny. This creates a deceptive pattern where the system optimizes for revenue under the guise of convenience.</p>

<h3 id="the-risk-of-falsely-imagined-competence">The Risk Of Falsely Imagined Competence</h3>

<p>Deception may not stem from malicious intent. It often manifests in AI as <strong>Imagined Competence</strong>. Large Language Models frequently sound authoritative even when incorrect. They present a false booking confirmation or an inaccurate summary with the same confidence as a verified fact. Users may naturally trust this confident tone. This mismatch creates a dangerous gap between system capability and user expectations.</p>

<p>We must design specifically to bridge this gap. If an agent fails to complete a task, the interface must signal that failure clearly. If the system is unsure, it must express uncertainty rather than masking it with polished prose.</p>

<h3 id="transparency-via-primitives">Transparency via Primitives</h3>

<p>The antidote to both sludge and hallucination is <strong>provenance</strong>. Every autonomous action requires a specific metadata tag explaining the origin of the decision. Users need the ability to inspect the logic chain behind the result.</p>

<p>To achieve this, we must <strong>translate primitives into practical answers</strong>. In software engineering, primitives refer to the core units of information or actions an agent performs. To the engineer, this looks like an API call or a logic gate. To the user, it must appear as a <strong>clear explanation</strong>.</p>

<p>The design challenge lies in mapping these technical steps to human-readable rationales. If an agent recommends a specific flight, the user needs to know why. The interface cannot hide behind a generic suggestion. It must expose the underlying primitive: <em>Logic: Cheapest_Direct_Flight</em> or <em>Logic: Partner_Airline_Priority</em>.</p>

<p>Figure 4 illustrates this translation flow. We take the raw system primitive &mdash; the actual code logic &mdash; and map it to a user-facing string. For instance, a primitive checking a calendar schedule a meeting becomes a clear statement: I’ve proposed a 4 PM meeting.</p>

<p>This level of transparency ensures the agent’s actions appear logical and beneficial. It allows the user to verify that the agent acted in their best interest. By exposing the primitives, we transform a black box into a glass box, ensuring users remain the final authority on their own digital lives.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="437"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg"
			
			sizes="100vw"
			alt="Translation flow"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <strong>Figure 4</strong>: Translating a primitive to an end explanation is key to explaining the behavior of Agentic AI. (<a href='https://files.smashing.media/articles/beyond-generative-rise-agentic-ai-user-centric-design/4-translation-flow.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="setting-the-stage-for-design">Setting The Stage For Design</h2>

<p>Building an agentic system requires a new level of psychological and behavioral understanding. It forces us to move beyond conventional usability testing and into the realm of <strong>trust</strong>, <strong>consent</strong>, and <strong>accountability</strong>. The research methods we’ve discussed, from probing mental models to simulating misbehavior and establishing new metrics, provide a necessary foundation. These practices are the essential tools for proactively identifying where an autonomous system might fail and, more importantly, how to repair the user-agent relationship when it does.</p>

<p>The shift to agentic AI is a <strong>redefinition of the user-system relationship</strong>. We are no longer designing for tools that simply respond to commands; we are designing for partners that act on our behalf. This changes the design imperative from efficiency and ease of use to <strong>transparency</strong>, <strong>predictability</strong>, and <strong>control</strong>.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aWhen%20an%20AI%20can%20book%20a%20flight%20or%20trade%20a%20stock%20without%20a%20final%20click,%20the%20design%20of%20its%20%e2%80%9con-ramps%e2%80%9d%20and%20%e2%80%9coff-ramps%e2%80%9d%20becomes%20paramount.%20It%20is%20our%20responsibility%20to%20ensure%20that%20users%20feel%20they%20are%20in%20the%20driver%e2%80%99s%20seat,%20even%20when%20they%e2%80%99ve%20handed%20over%20the%20wheel.%0a&url=https://smashingmagazine.com%2f2026%2f01%2fbeyond-generative-rise-agentic-ai-user-centric-design%2f">
      
When an AI can book a flight or trade a stock without a final click, the design of its “on-ramps” and “off-ramps” becomes paramount. It is our responsibility to ensure that users feel they are in the driver’s seat, even when they’ve handed over the wheel.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>This new reality also elevates the role of the UX researcher. We become the custodians of user trust, working collaboratively with engineers and product managers to define and test the guardrails of an agent’s autonomy. Beyond being researchers, we become advocates for user control, transparency, and the ethical safeguards within the development process. By translating primitives into practical questions and simulating worst-case scenarios, we can build robust systems that are both powerful and safe.</p>

<p>This article has outlined the “what” and “why” of researching agentic AI. It has shown that our traditional toolkits are insufficient and that we must adopt new, forward-looking methodologies. The next article will build upon this foundation, providing the specific design patterns and organizational practices that make an agent’s utility transparent to users, ensuring they can harness the power of agentic AI with confidence and control. The future of UX is about making systems trustworthy.</p>

<p>For additional understanding of agentic AI, you can explore the following resources:</p>

<ul>
<li><a href="https://www.google.com/search?q=https://ai.googleblog.com/blog/topic/agentic-ai/">Google AI Blog on Agentic AI</a></li>
<li><a href="https://www.microsoft.com/en-us/research/project/agent-ai/">Microsoft’s research on AI Agents</a></li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Andy Clarke</author><title>Smashing Animations Part 8: Theming Animations Using CSS Relative Colour</title><link>https://www.smashingmagazine.com/2026/01/smashing-animations-part-8-css-relative-colour/</link><pubDate>Wed, 14 Jan 2026 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2026/01/smashing-animations-part-8-css-relative-colour/</guid><description>CSS relative colour values are now widely supported. In this article, pioneering author and web designer &lt;a href="https://stuffandnonsense.co.uk/">Andy Clarke&lt;/a> shares practical techniques for using them to theme and animate SVG graphics.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2026/01/smashing-animations-part-8-css-relative-colour/" />
              <title>Smashing Animations Part 8: Theming Animations Using CSS Relative Colour</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Smashing Animations Part 8: Theming Animations Using CSS Relative Colour</h1>
                  
                    
                    <address>Andy Clarke</address>
                  
                  <time datetime="2026-01-14T10:00:00&#43;00:00" class="op-published">2026-01-14T10:00:00+00:00</time>
                  <time datetime="2026-01-14T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>I’ve recently refreshed the animated graphics on <a href="https://stuffandnonsense.co.uk/">my website</a> with a new theme and a group of pioneering characters, putting into practice plenty of the techniques I shared in <a href="https://www.smashingmagazine.com/author/andy-clarke/">this series</a>. A few of my animations change appearance when someone interacts with them or at different times of day.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/blog">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="341"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png"
			
			sizes="100vw"
			alt="Graphics from Andy’s website"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this animated SVG on <a href='https://stuffandnonsense.co.uk/blog'>my website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/1-andy-website-animated-graphics.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The colours in the graphic atop <a href="https://stuffandnonsense.co.uk/blog">my blog pages</a> change from morning until night every day. Then, there’s the <a href="https://stuffandnonsense.co.uk/blog/let-it-snow">snow mode</a>, which adds chilly colours and a wintery theme, courtesy of an overlay layer and a blending mode.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="359"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png"
			
			sizes="100vw"
			alt="Snow mode applied to the town background"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Snow mode allows my pioneer town background to adapt throughout the day. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/2-snow-mode.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>While working on this, I started to wonder whether CSS relative colour values could give me more control while also simplifying the process.</p>

<p><strong>Note</strong>: <em>In this tutorial, I’ll focus on relative colour values and the OKLCH colour space for theming graphics and animations. If you want to dive deep into relative colour, Ahmad Shadeed created a superb <a href="https://ishadeed.com/article/css-relative-colors/">interactive guide</a>. As for colour spaces, gamuts, and OKLCH, our own Geoff Graham <a href="https://www.smashingmagazine.com/2023/08/oklch-color-spaces-gamuts-css/">wrote</a> about them.</em></p>

<div class="refs">
  <ul><li><a href="https://www.smashingmagazine.com/2025/05/smashing-animations-part-1-classic-cartoons-inspire-css/"><strong>Smashing Animations Part 1</strong>: How Classic Cartoons Inspire Modern CSS</a></li><li><a href="https://www.smashingmagazine.com/2025/05/smashing-animations-part-2-css-masking-add-extra-dimension/"><strong>Smashing Animations Part 2</strong>: How CSS Masking Can Add An Extra Dimension</a></li><li><a href="https://www.smashingmagazine.com/2025/05/smashing-animations-part-3-smil-not-dead/"><strong>Smashing Animations Part 3</strong>: SMIL’s Not Dead Baby, SMIL’s Not Dead</a></li><li><a href="https://www.smashingmagazine.com/2025/06/smashing-animations-part-4-optimising-svgs/"><strong>Smashing Animations Part 4</strong>: Optimising SVGs</a></li><li><a href="https://www.smashingmagazine.com/2025/10/smashing-animations-part-5-building-adaptive-svgs/"><strong>Smashing Animations Part 5</strong>: Building Adaptive SVGs With <code>&lt;symbol&gt;</code>, <code>&lt;use&gt;</code>, And CSS Media Queries</a></li><li><a href="https://www.smashingmagazine.com/2025/11/smashing-animations-part-6-svgs-css-custom-properties/"><strong>Smashing Animations Part 6</strong>: Magnificent SVGs With <code>&lt;use&gt;</code> And CSS Custom Properties</a></li><li><a href="https://www.smashingmagazine.com/2025/12/smashing-animations-part-7-recreating-toon-text-css-svg/"><strong>Smashing Animations Part 7</strong>: Recreating Toon Text With CSS And SVG</a></li></ul>
</div>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="how-cartoon-animation-taught-me-to-reuse-everything">How Cartoon Animation Taught Me To Reuse Everything</h2>

<p>The <a href="https://en.wikipedia.org/wiki/Hanna-Barbera">Hanna-Barbera</a> animated series I grew up watching had budgets far lower than those available when William Hanna and Joseph Barbera produced <em>Tom and Jerry</em> shorts at MGM Cartoons. This meant the animators needed to develop techniques to work around their cost restrictions.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="196"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png"
			
			sizes="100vw"
			alt="Repeated use of elements in the Yogi Bear Show"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/3-yogi-bear-show.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Repeated use of elements was key. Backgrounds were reused whenever possible, with zooms and overlays helping construct new scenes from the same artwork. It was born of necessity, but it also encouraged thinking in terms of series rather than individual scenes.</p>

<h2 id="the-problem-with-manually-updating-colour-palettes">The problem With Manually Updating Colour Palettes</h2>

<p>Let’s get straight to my challenge. In Toon Titles like this one &mdash; based on the 1959 Yogi Bear Show episode “Lullabye-Bye Bear” &mdash; and my work generally, palettes are limited to a select few colours.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png"
			
			sizes="100vw"
			alt="Illustration of Yogi Bear asleep in a hammock tied between two thin, white trees. Andy Clarke’s Toon Titles is displayed above Yogi in cartoon-style typography."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this on my <a href='https://stuffandnonsense.co.uk/toon-titles/24b.html'>Toon Titles website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/4-yogi-bear.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I create shades and tints from what I call my “foundation” colour to expand the palette without adding more hues.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png"
			
			sizes="100vw"
			alt="Colour palette of a foundation colour"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Colour palette with shades and tints of a foundation colour. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/5-colour-palette.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>In <a href="https://www.sketch.com">Sketch</a>, I work in the <a href="https://www.smashingmagazine.com/2021/07/hsl-colors-css/">HSL colour space</a>, so this process involves increasing or decreasing the lightness value of my foundation colour. Honestly, it’s not an arduous task &mdash; but choosing a different foundation colour requires creating a whole new set of shades and tints. Doing that manually, again and again, quickly becomes laborious.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png"
			
			sizes="100vw"
			alt="Shades and tints of a different foundation colour."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Shades and tints of a different foundation colour. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/6-foundation-colour.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I mentioned the HSL &mdash; <strong>H</strong> (hue), S (saturation), and <strong>L</strong> (lightness) &mdash; colour space, but that’s just one of several ways to describe colour.</p>

<p>RGB &mdash; <strong>R</strong> (red), <strong>G</strong> (green), <strong>B</strong> (blue) &mdash; is probably the most familiar, at least in its Hex form.</p>

<p>There’s also LAB &mdash; <strong>L</strong> (lightness), <strong>A</strong> (green–red), <strong>B</strong> (blue–yellow) &mdash; and the newer, but now widely supported LCH &mdash; <strong>L</strong> (lightness), <strong>C</strong> (chroma), <strong>H</strong> (hue) &mdash; model in its OKLCH form. With LCH &mdash; specifically OKLCH in CSS &mdash; I can adjust the lightness value of my foundation colour.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="334"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png"
			
			sizes="100vw"
			alt="Lightness changes to the foundation colour."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Lightness changes to my foundation colour. Chroma and Hue remain the same. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/7-lightness-change-foundation-colour.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Or I can alter its <em>chroma</em>. LCH chroma and HSL saturation both describe the intensity or richness of a colour, but they do so in different ways. LCH gives me a wider range and more predictable blending between colours.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="334"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png"
			
			sizes="100vw"
			alt="Chroma changes to the foundation colour"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Chroma changes to my foundation colour. Lightness and Hue remain the same. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/8-chroma-changes-foundation-colour.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I can also alter the hue to create a palette of colours that share the same lightness and chroma values. In both HSL and LCH, the hue spectrum starts at red, moves through green and blue, and returns to red.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="334"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png"
			
			sizes="100vw"
			alt="Hue changes to the foundation colour."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Hue changes to my foundation colour. Lightness and Chrome remain the same. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/9-hue-changes-foundation-colour.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="why-oklch-changed-how-i-think-about-colour">Why OKLCH Changed How I Think About Colour</h2>

<p>Browser support for the OKLCH colour space <a href="https://caniuse.com/wf-oklab">is now widespread</a>, even if design tools &mdash; including Sketch &mdash; haven’t caught up. Fortunately, that shouldn’t stop you from using OKLCH. Browsers will happily convert Hex, HSL, LAB, and RGB values into OKLCH for you. You can define a CSS custom property with a foundation colour in any space, including Hex:</p>

<pre><code class="language-css">/&#42; Foundation colour &#42;/
--foundation: &#35;5accd6;
</code></pre>

<p>Any colours derived from it will be converted into OKLCH automatically:</p>

<pre><code class="language-css">--foundation-light: oklch(from var(--foundation) [...]; }
--foundation-mid: oklch(from var(--foundation) [...]; }
--foundation-dark: oklch(from var(--foundation) [...]; }
</code></pre>

<h2 id="relative-colour-as-a-design-system">Relative Colour As A Design System</h2>

<p>Think of relative colour as saying: <em>“Take this colour, tweak it, then give me the result.”</em> There are two ways to adjust a colour: absolute changes and proportional changes. They look similar in code, but behave very differently once you start swapping foundation colours. Understanding that difference is what can turn using relative colour into a system.</p>

<pre><code class="language-css">/&#42; Foundation colour &#42;/
--foundation: &#35;5accd6;
</code></pre>

<p>For example, the lightness value of my foundation colour is <code>0.7837</code>, while a darker version has a value of <code>0.5837</code>. To calculate the difference, I subtract the lower value from the higher one and apply the result using a <code>calc()</code> function:</p>

<pre><code class="language-css">--foundation-dark: 
  oklch(from var(--foundation)
  calc(l - 0.20) c h);
</code></pre>

<p>To achieve a lighter colour, I add the difference instead:</p>

<pre><code class="language-css">--foundation-light:
  oklch(from var(--foundation)
  calc(l + 0.10) c h);
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="334"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png"
			
			sizes="100vw"
			alt="Calculations of the difference between the foundation colour and Lightness, Chroma, and Hue-adjusted colours."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Calculating the difference between my foundation colour and Lightness, Chroma, and Hue-adjusted colours. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/10-calculating-colour-difference.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Chroma adjustments follow the same process. To reduce the intensity of my foundation colour from <code>0.1035</code> to <code>0.0035</code>, I subtract one value from the other:</p>

<pre><code class="language-css">oklch(from var(--foundation)
l calc(c - 0.10) h);
</code></pre>

<p>To create a palette of hues, I calculate the difference between the hue value of my foundation colour (<code>200</code>) and my new hue (<code>260</code>):</p>

<pre><code class="language-css">oklch(from var(--foundation)
l c calc(h + 60));
</code></pre>

<p>Those calculations are absolute. When I subtract a fixed amount, I’m effectively saying, <em>“Always subtract this much.”</em> The same applies when adding fixed values:</p>

<pre><code class="language-css">calc(c - 0.10)
calc(c + 0.10)
</code></pre>

<p>I learned the limits of this approach the hard way. When I relied on subtracting fixed chroma values, colours collapsed towards grey as soon as I changed the foundation. A palette that worked for one colour fell apart for another.</p>

<p>Multiplication behaves differently. When I multiply chroma, I’m telling the browser: <em>“Reduce this colour’s intensity by a proportion.”</em> The relationship between colours remains intact, even when the foundation changes:</p>

<pre><code class="language-css">calc(c &#42; 0.10)
</code></pre>

<div class="partners__lead-place"></div>

<h2 id="my-move-it-scale-it-rotate-it-rules">My Move It, Scale It, Rotate It Rules</h2>

<ul>
<li><strong>Move</strong> lightness (add or subtract),</li>
<li><strong>Scale</strong> chroma (multiply),</li>
<li><strong>Rotate</strong> hue (add or subtract degrees).</li>
</ul>

<p>I scale chroma because I want intensity changes to stay proportional to the base colour. Hue relationships are rotational, so multiplying hue makes no sense. Lightness is perceptual and absolute &mdash; multiplying it often produces odd results.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="334"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png"
			
			sizes="100vw"
			alt="Lightness: Move it. Chroma: Scale it. Hue: Rotate it"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Lightness: Move it. Chroma: Scale it. Hue: Rotate it. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/11-move-scale-rotate.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="from-one-colour-to-an-entire-theme">From One Colour To An Entire Theme</h2>

<p>Relative colour allows me to define a foundation colour and generate every other colour I need &mdash; fills, strokes, gradient stops, shadows &mdash; from it. At that point, colour stops being a palette and starts being a system.</p>

<blockquote>SVG illustrations tend to reuse the same few colours across fills, strokes, and gradients. Relative colour lets you define those relationships once and reuse them everywhere &mdash; much like animators reused backgrounds to create new scenes.</blockquote>

<p>Change the foundation colour once, and every derived colour updates automatically, without recalculating anything by hand. Outside of animated graphics, I could use this same approach to define colours for the states of interactive elements such as buttons and links.</p>

<p>The foundation colour I used in my “Lullabye-Bye Bear” Toon Title is a cyan-looking blue. The background is a radial gradient between my foundation and a darker version.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/toon-titles/24b.html">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png"
			
			sizes="100vw"
			alt="“Lullabye-Bye Bear” Toon Title"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this on my <a href='https://stuffandnonsense.co.uk/toon-titles/24b.html'>Toon Titles website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/12-toon-titles-website.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To create alternative versions with entirely different moods, I only need to change the foundation colour:</p>

<pre><code class="language-css">--foundation: &#35;5accd6;
--grad-end: var(--foundation);
--grad-start: oklch(from var(--foundation)
  calc(l - 0.2357) calc(c &#42; 0.833) h);
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/toon-titles/24b.html">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="171"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png"
			
			sizes="100vw"
			alt="Three alternative versions of the “Lullabye-Bye Bear” Toon Title"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Use the colour picker on my <a href='https://stuffandnonsense.co.uk/toon-titles/24b.html'>Toon Titles website</a> to see this in action. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/13-toon-titles-website.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To bind those custom properties to my SVG gradient without duplicating colour values, I replaced hard-coded <code>stop-color</code> values with inline styles:</p>

<div class="break-out">
<pre><code class="language-svg">&lt;defs&gt;
  &lt;radialGradient id="bg-grad" […]&gt;
    &lt;stop offset="0%" style="stop-color: var(--grad-end);" /&gt;
    &lt;stop offset="100%" style="stop-color: var(--grad-start);" /&gt;
  &lt;/radialGradient&gt;
&lt;/defs&gt;
</code></pre>
</div>
  

<pre><code class="language-svg">&lt;path fill="url(#bg-grad)" fill="#5DCDD8" d="[...]"/&gt;
</code></pre>

<p>Next, I needed to ensure that my <a href="https://stuffandnonsense.co.uk/toon-text/index.html">Toon Text</a> always contrasts with whatever foundation colour I choose. A <code>180deg</code> hue rotation produces a complementary colour that certainly pops &mdash; but can vibrate uncomfortably:</p>

<pre><code class="language-css">.text-light {
  fill: oklch(from var(--foundation)
    l c calc(h + 180));
}
</code></pre>

<p>A <code>90°</code> shift produces a vivid secondary colour without being fully complementary:</p>

<pre><code class="language-css">.text-light {
  fill: oklch(from var(--foundation)
    l c calc(h - 90));
}
</code></pre>

<p>My recreation of Quick Draw McGraw’s 1959 Toon Title “El Kabong“ uses the same techniques but with a more varied palette. For example, there’s another radial gradient between the foundation colour and a darker shade.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png"
			
			sizes="100vw"
			alt="An animated still of Quick Draw McGraw swinging from a rope going from left to right against a purple gradient background. Andy Clarke’s Toon Titles is displayed above him in cartoon-style typography. A silhouetted building and palm tree are positioned in the bottom-right corner."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this on my <a href='https://stuffandnonsense.co.uk/toon-titles/quick-draw-4b.html'>Toon Titles website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/14-quick-draw-mcgraw.png'>Large preview</a>)
    </figcaption>
  
</figure>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/toon-titles/quick-draw-4b.html">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="167"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png"
			
			sizes="100vw"
			alt="Three alternative versions of Quick Draw McGraw’s 1959 Toon Title “El Kabong“"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Use the colour picker on my <a href='https://stuffandnonsense.co.uk/toon-titles/quick-draw-4b.html'>Toon Titles website</a> to see this in action. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/15-quick-draw-mcgraw-toon-titles.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The building and tree in the background are simply different shades of the same foundation colour. For those paths, I needed two additional <code>fill</code> colours:</p>

<pre><code class="language-css">.bg-mid {
  fill: oklch(from var(--foundation)
    calc(l - 0.04) calc(c &#42; 0.91) h);
}

.bg-dark {
  fill: oklch(from var(--foundation)
    calc(l - 0.12) calc(c &#42; 0.64) h);
}
</code></pre>

<h2 id="when-the-foundations-start-to-move">When The Foundations Start To Move</h2>

<p>So far, everything I’ve shown has been static. Even when someone uses a colour picker to change the foundation colour, that change happens instantly. But animated graphics rarely stand still &mdash; the clue is in the name. So, if colour is part of the system, there’s no reason it can’t animate, too.</p>

<p>To animate the foundation colour, I first need to split it into its OKLCH channels &mdash; lightness, chroma, and hue. But there’s an important extra step: I need to register those values as <em>typed</em> custom properties. But what does that mean?</p>

<p>By default, a browser doesn’t know whether a CSS custom property value represents a colour, length, number, or something else entirely. That often means <a href="https://css-tricks.com/what-you-need-to-know-about-css-color-interpolation/">they can’t be interpolated smoothly during animation</a>, and jump from one value to the next.</p>

<p>Registering a custom property tells the browser the type of value it represents and how it should behave over time. In this case, I want the browser to treat my colour channels as numbers so they can be animated smoothly.</p>

<pre><code class="language-css">@property --f-l {
  syntax: "&lt;number&gt;";
  inherits: true;
  initial-value: 0.40;
}

@property --f-c {
  syntax: "&lt;number&gt;";
  inherits: true;
  initial-value: 0.11;
}

@property --f-h {
  syntax: "&lt;number&gt;";
  inherits: true;
  initial-value: 305;
}
</code></pre>

<p>Once registered, these custom properties behave like native CSS. The browser can interpolate them frame-by-frame. I then rebuild the foundation colour from those channels:</p>

<pre><code class="language-css">--foundation: oklch(var(--f-l) var(--f-c) var(--f-h));
</code></pre>

<p>This makes the foundation colour become animatable, just like any other numeric value. Here’s a simple “breathing” animation that gently shifts lightness over time:</p>

<pre><code class="language-css">@keyframes breathe {
  0%, 100% { --f-l: 0.36; }
  50% { --f-l: 0.46; }
}

.toon-title {
  animation: breathe 10s ease-in-out infinite;
}
</code></pre>

<p>Because every other colour in fills, gradients, and strokes is derived from <code>--foundation</code>, they all animate together, and nothing needs to be updated manually.</p>

<div class="partners__lead-place"></div>

<h2 id="one-animated-colour-many-effects">One Animated Colour, Many Effects</h2>

<p>At the start of this process, I wondered whether CSS relative colour values could offer more possibilities while also making them simpler to implement. I recently added a new gold mine background to my website’s <a href="https://stuffandnonsense.co.uk/contact">contact page</a>, and the first iteration included oil lamps that glow and swing.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/contact">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="305"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png"
			
			sizes="100vw"
			alt="A group of seven illustrated western characters in an underground gold mine scene."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this animated SVG on <a href='https://stuffandnonsense.co.uk/contact'>my website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/16-gold-mine-scene.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I wanted to explore how animating CSS relative colours could make the mine interior more realistic by tinting it with colours from the lamps. I wanted them to affect the world around them, the way real light does. So, rather than animating multiple colours, I built a tiny lighting system that animates just one colour.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="305"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png"
			
			sizes="100vw"
			alt="Overlay layer applied to the SVG"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Adding an overlay layer to my SVG. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/17-overlay-layer-svg.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>My first task was to slot an overlay layer between the background and my lamps:</p>

<pre><code class="language-svg">&lt;path 
  id="overlay"
  fill="var(--overlay-tint)" 
  [...] 
  style="mix-blend-mode: color"
/&gt;
</code></pre>

<p>I used <code>mix-blend-mode: color</code> because that tints what’s beneath it while preserving the underlying luminance. As I only want the overlay to be visible when animations are turned on, I made the overlay opt-in:</p>

<pre><code class="language-css">.svg-mine &#35;overlay {
  display: none;
}
  
@media (prefers-reduced-motion: no-preference) {
  .svg-mine[data-animations=on] &#35;overlay {
    display: block;
    opacity: 0.5;
  }
}
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="305"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png"
			
			sizes="100vw"
			alt="An overlay applied to the gold mine scene illuminates the background, making it brighter than the foreground."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      The overlay layer tints what’s beneath it. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/18-overlay-gold-mine-scene.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The overlay was in place, but not yet connected to the lamps. I needed a light source. My lamps are simple, and each one contains a <code>circle</code> element that I blurred with a filter. The <code>filter</code> produces a very soft blur over the entire circle.</p>

<div class="break-out">
<pre><code class="language-svg">&lt;filter id="lamp-glow-1" x="-120%" y="-120%" width="340%" height="340%"&gt;
  &lt;feGaussianBlur in="SourceGraphic" stdDeviation="56"/&gt;
&lt;/filter&gt;
</code></pre>
</div>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="305"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png"
			
			sizes="100vw"
			alt="Added oil lamps to the gold mine scene"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Adding oil lamps to my scene. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/19-oil-lamps.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Instead of animating the overlay and lamps separately, I animate a single “flame” colour token and derive everything else from that. First, I register three typed custom properties for OKLCH channels:</p>

<pre><code class="language-css">@property --fl-l {
  syntax: "&lt;number&gt;"; 
  inherits: true;
  initial-value: 0.86;
}
@property --fl-c {
  syntax: "&lt;number&gt;";
  inherits: true;
  initial-value: 0.12;
}
@property --fl-h {
  syntax: "&lt;number&gt;";
  inherits: true;
  initial-value: 95;
}
</code></pre>

<p>I animated those channels, deliberately pushing a few frames towards orange so the flicker reads clearly as firelight:</p>

<div class="break-out">
<pre><code class="language-css">@keyframes flame {
  0%, 100% { --fl-l: 0.86; --fl-c: 0.12; --fl-h: 95; }
  6% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 92; }
  12% { --fl-l: 0.83; --fl-c: 0.14; --fl-h: 100; }
  18% { --fl-l: 0.88; --fl-c: 0.11; --fl-h: 94; }
  24% { --fl-l: 0.82; --fl-c: 0.16; --fl-h: 82; }
  30% { --fl-l: 0.90; --fl-c: 0.12; --fl-h: 90; }
  36% { --fl-l: 0.79; --fl-c: 0.17; --fl-h: 76; }
  44% { --fl-l: 0.87; --fl-c: 0.12; --fl-h: 96; }
  52% { --fl-l: 0.81; --fl-c: 0.15; --fl-h: 102; }
  60% { --fl-l: 0.89; --fl-c: 0.11; --fl-h: 93; }
  68% { --fl-l: 0.83; --fl-c: 0.16; --fl-h: 85; }
  76% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 91; }
  84% { --fl-l: 0.85; --fl-c: 0.14; --fl-h: 98; }
  92% { --fl-l: 0.80; --fl-c: 0.17; --fl-h: 74; }
}
</code></pre>
</div>

<p>Then I scoped that animation to the SVG, so the shared variables are available to both the lamps and my overlay:</p>

<div class="break-out">
<pre><code class="language-css">@media (prefers-reduced-motion: no-preference) {
  .svg-mine[data-animations=on] {
    animation: flame 3.6s infinite linear;
    isolation: isolate;

    /&#42; Build a flame colour from animated channels &#42;/
    --flame: oklch(var(--fl-l) var(--fl-c) var(--fl-h));

    /&#42; Lamp colour derived from flame &#42;/
    --lamp-core: oklch(from var(--flame) calc(l + 0.05) calc(c &#42; 0.70) h);
  
    /&#42; Overlay tint derived from the same flame &#42;/
    --overlay-tint: oklch(from var(--flame)
      calc(l + 0.06) calc(c &#42; 0.65) calc(h - 10));
  }
}
</code></pre>
</div>

<p>Finally, I applied those derived colours to the glowing lamps and the overlay they affect:</p>

<pre><code class="language-css">@media (prefers-reduced-motion: no-preference) {
  .svg-mine[data-animations=on] &#35;mine-lamp-1 &gt; circle,
  .svg-mine[data-animations=on] &#35;mine-lamp-2 &gt; circle {
    fill: var(--lamp-core);
  }
  
  .svg-mine[data-animations=on] &#35;overlay {
    display: block;
    fill: var(--overlay-tint);
    opacity: 0.5;
  }
}
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="305"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png"
			
			sizes="100vw"
			alt="The lamps and overlay are connected."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      The lamps and overlay are connected. (<a href='https://files.smashing.media/articles/smashing-animations-part-8-css-relative-colour/20-lamps-overlay-connected.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>When the flame shifts toward orange, the lamps warm up, and the scene warms with them. When the flame cools, everything settles together. The best part is that nothing is written manually. If I change the foundation colour or tweak the flame animation ranges, the entire lighting system updates simultaneously.</p>

<p>You can see <a href="https://stuffandnonsense.co.uk/contact">the final result on my website</a>.</p>

<h2 id="reuse-repurpose-revisited">Reuse, Repurpose, Revisited</h2>

<p>Those Hanna-Barbera animators were forced to repurpose elements out of necessity, but I reuse colours because it makes my work <strong>more consistent</strong> and <strong>easier to maintain</strong>. CSS relative colour values allow me to:</p>

<ul>
<li>Define a single foundation colour,</li>
<li>Describe how other colours relate to it,</li>
<li>Reuse those relationships everywhere, and</li>
<li>Animate the system by changing one value.</li>
</ul>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aRelative%20colour%20doesn%e2%80%99t%20just%20make%20theming%20easier.%20It%20encourages%20a%20way%20of%20thinking%20where%20colour,%20like%20motion,%20is%20intentional%20%e2%80%94%20and%20where%20changing%20one%20value%20can%20transform%20an%20entire%20scene%20without%20rewriting%20the%20work%20beneath%20it.%0a&url=https://smashingmagazine.com%2f2026%2f01%2fsmashing-animations-part-8-css-relative-colour%2f">
      
Relative colour doesn’t just make theming easier. It encourages a way of thinking where colour, like motion, is intentional — and where changing one value can transform an entire scene without rewriting the work beneath it.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Vitaly Friedman</author><title>UX And Product Designer’s Career Paths In 2026</title><link>https://www.smashingmagazine.com/2026/01/ux-product-designer-career-paths/</link><pubDate>Mon, 12 Jan 2026 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2026/01/ux-product-designer-career-paths/</guid><description>How to shape your career path for 2026, with decision trees for designers and a UX skills self-assessment matrix. The only limits for tomorrow are the doubts we have today. Brought to you by &lt;a href="https://smart-interface-design-patterns.com/">Smart Interface Design Patterns&lt;/a>, a &lt;strong>friendly video course on UX&lt;/strong> and design patterns by Vitaly.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2026/01/ux-product-designer-career-paths/" />
              <title>UX And Product Designer’s Career Paths In 2026</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>UX And Product Designer’s Career Paths In 2026</h1>
                  
                    
                    <address>Vitaly Friedman</address>
                  
                  <time datetime="2026-01-12T10:00:00&#43;00:00" class="op-published">2026-01-12T10:00:00+00:00</time>
                  <time datetime="2026-01-12T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>As the new year begins, I often find myself in a strange place &mdash; reflecting back at the previous year or looking forward to the year ahead. And as I speak with colleagues and friends at the time, it typically doesn’t take long for a conversation about <strong>career trajectory</strong> to emerge.</p>

<p>So I thought I’d share a few thoughts on <strong>how to shape your career path</strong> as we are looking ahead to 2026. Hopefully you’ll find it useful.</p>

<h2 id="run-a-retrospective-for-last-year">Run A Retrospective For Last Year</h2>

<p>To be honest, for many years, I was mostly reacting. Life was happening <em>to</em> me, rather than me shaping the life that I was living. I was <strong>making progress reactively</strong> and I was looking out for all kinds of opportunities. It was easy and quite straightforward &mdash; I was floating and jumping between projects and calls and making things work as I was going along.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.linkedin.com/posts/lilyyue_uxdesign-careergrowth-productdesign-activity-7343261653901144066-8nLf?utm_source=social_share_send&amp;utm_medium=member_desktop_web&amp;rcm=ACoAABGhVGkBT-YMeCMZd9fKgSaE_H8BrQil438">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="996"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg"
			
			sizes="100vw"
			alt="An overview of diverse career paths, from UX research to design lead, to senior designer and design consultant."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.linkedin.com/posts/lilyyue_uxdesign-careergrowth-productdesign-activity-7343261653901144066-8nLf/'>Diverse career paths for UX Designers</a>, a helpful overview by Lili Yue. You might find yourself doing a little bit of everything in this overview &mdash; but you need to know where you want to go next. (<a href='https://files.smashing.media/articles/product-designer-career-paths/4-career-paths-ux-designers.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Years ago, my wonderful wife introduced <strong>one little annual ritual</strong> which changed that dynamic entirely. By the end of each year, we sit with nothing but paper and pencil and run a thorough <strong>retrospective of the past year</strong> &mdash; successes, mistakes, good moments, bad moments, things we loved, and things we wanted to change.</p>

<p>We look back at our memories, projects, and events that stood out that year. And then we take notes for where we stand in terms of personal growth, professional work, and social connections &mdash; and <strong>how we want to grow</strong>.</p>

<p>These are <strong>the questions</strong> I’m trying to answer there:</p>

<ul>
<li>What did I find <strong>most rewarding</strong> and fulfilling last year?</li>
<li>What <strong>fears and concerns slowed me down</strong> the most?</li>
<li>What could I <strong>leave behind</strong>, give away or simplify?</li>
<li>What tasks would be <strong>good to delegate</strong> or automate?</li>
<li>What are my <strong>3 priorities to grow</strong> this upcoming year?</li>
<li>What <strong>times do I block</strong> in my calendar for my priorities?</li>
</ul>

<p>It probably sounds quite cliche, but these 4&ndash;5h of our time every year set a <strong>foundation for changes</strong> to introduce for the next year. This little exercise shapes the trajectory that I’ll be designing and prioritizing next year. I can’t recommend it enough.</p>

<h2 id="ux-skills-self-assessment-matrix">UX Skills Self-Assessment Matrix</h2>

<p>Another little tool that I found helpful for professional growth is <a href="https://www.figma.com/community/file/1142203484282738794/design-skills-matrix">UX Skills Self-Assessment Matrix</a> (Figma template) by Maigen Thomas. It’s a neat little tool that’s designed to help you understand what you’d like to do more of, what you’d prefer to do less, and where your <strong>current learning curve</strong> lies vs. where you feel <strong>confident in your expertise</strong>.</p>














<figure class="
  
  
  ">
  
    <a href="https://www.figma.com/community/file/1142203484282738794/design-skills-matrix">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="1223"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg"
			
			sizes="100vw"
			alt="A ‘Design Skills Self-Assessment Matrix’ with a colorful header and a grid below plotting skills across ‘Still Learning,’ ‘Want to Do More,’ ‘Expert at This,’ and ‘Want to Do Less’ quadrants."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.figma.com/community/file/1142203484282738794/design-skills-matrix'>A neat little tool</a> to identify where you stand, what you want to do less of, more of, and what you’d like to learn. (<a href='https://files.smashing.media/articles/product-designer-career-paths/2-design-skills-self-assessment-matrix.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The exercise typically takes around 20&ndash;30 minutes, and it helps identify the <strong>UX skills with a sweet spot</strong> &mdash; typically the upper half of the canvas. You’ll also pinpoint areas where you’re improving, and those where you are already pretty good at. It’s a neat reality check &mdash; and a great reminder once you review it year after year. Highly recommended!</p>

<h2 id="ux-career-levels-for-design-systems-teams">UX Career Levels For Design Systems Teams</h2>

<p>A while back, <a href="https://www.linkedin.com/in/javiercuello/?lipi=urn%3Ali%3Apage%3Ad_flagship3_pulse_read%3BarGUwB3ET%2FyNMblHCHHbCg%3D%3D">Javier Cuello</a> has put together a Career Levels For Design System Teams (Figma Kit), a neat little helper for product designers looking to transition into design systems teams or managers building a career matrix for them. The model maps progression levels (Junior, Semi-Senior, Senior, and Staff) to key development areas, with skills and responsibilities required at each stage.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.figma.com/community/file/1444342030560583543/design-systems-product-design-career-levels">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="877"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg"
			
			sizes="100vw"
			alt="UX Career Levels for design system teams"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Career Levels For Design System Teams (Figma Kit). Kindly put together by Javier Cuello. (<a href='https://files.smashing.media/articles/product-designer-career-paths/5-ux-career-levels.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>What I find quite valuable in Javier’s model is the mapping of strategy and impact, along with systematic thinking and governance. While as designers we often excel at tactical design &mdash; from elegant UI components to file organization in Figma &mdash; we often lag a little bit behind in strategic decisions.</p>

<p>To a large extent, the difference between levels of seniority is moving from tactical initiatives to strategic decisions. It’s proactively looking for organizational challenges that a system can help with. It’s finding and inviting key people early. It’s also about embedding yourself in other teams when needed.</p>

<p>But it’s also keeping an eye out for situations when design systems fail, and paving the way to make it more difficult to fail. And: adapting the workflow around the design system to ship on a tough deadline when needed, but with a viable plan of action on how and when to pay back accumulating UX debt.</p>

<h2 id="find-your-product-design-career-path">Find Your Product Design Career Path</h2>

<p>When we speak about career trajectory, it’s almost always assumed that the career progression inevitably leads to <strong>management</strong>. However, this hasn’t been a path I preferred, and it isn’t always the ideal path for everyone.</p>

<p>Personally, I prefer to work on intricate fine details of UX flows and deep dive into <strong>complex UX challenges</strong>. However, eventually it might feel like you’ve stopped growing &mdash; perhaps you’ve hit a ceiling in your organization, or you have little room for exploration and learning. So where do you go from there?</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://uxdesign.cc/fixing-product-design-career-paths-with-the-mirror-model-76152b7e547?sk=v2%2F0a6cb162-4def-4f1c-ac5e-b145597646c7">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="562"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg"
			
			sizes="100vw"
			alt="A complex flowchart titled ‘Product Design Career Paths: The Mirror Model’ in blue, detailing two parallel career progression tracks: individual contributor and management."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://uxdesign.cc/fixing-product-design-career-paths-with-the-mirror-model-76152b7e547?sk=v2%2F0a6cb162-4def-4f1c-ac5e-b145597646c7'>The Mirror Model</a> (<a href='https://drive.google.com/file/d/1BePJyrd8q0D1mVgIV2h8ghds8IbbyzBR/view'>PDF</a>) is a helpful way to visualize creative and managerial paths with equivalent influence and compensation. (<a href='https://files.smashing.media/articles/product-designer-career-paths/3-producst-design-career-paths-mirror-model.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>A helpful model to think about your next steps is to consider Ryan Ford’s <a href="https://uxdesign.cc/fixing-product-design-career-paths-with-the-mirror-model-76152b7e547?sk=v2%2F0a6cb162-4def-4f1c-ac5e-b145597646c7">Mirror Model</a>. It explores <strong>career paths and expectations</strong> that you might want to consider to advocate for a position or influence that you wish to achieve next.</p>

<p>That’s typically something you might want to study and <strong>decide on your own first</strong>, and then bring it up for discussion. Usually, there are internal opportunities out there. So before changing the company, you can switch teams, or you could shape a more fulfilling role <strong>internally</strong>.</p>

<p>You just need to find it first. Which brings us to the next point.</p>

<h2 id="proactively-shaping-your-role">Proactively Shaping Your Role</h2>

<p>I keep reminding myself of <a href="https://www.linkedin.com/in/jasonmesut?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAAAAawX0BwaORuqGb58dyVh03pJIPpuU6s68&amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_pulse_read%3BarGUwB3ET%2FyNMblHCHHbCg%3D%3D">Jason Mesut</a>’s observation that when we speak about career ladders, it assumes that we can either go up, down, or fall off. But in reality, you can <strong>move up, move down, and move sideways</strong>. As Jason says, “promoting just the vertical progression doesn’t feel healthy, especially in such a diverse world of work, and diverse careers ahead of us all.”</p>

<p>So, in the attempt to climb up, perhaps consider also moving sideways. <strong>Zoom out and explore</strong> where your interests are. Focus on the much-needed intersection between business needs and user needs. Between problem space and solution space. Between strategic decisions and operations. Then zoom in. In the end, you might not need to climb anything &mdash; but rather just find that right spot that brings your expertise to light and makes the biggest impact.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.linkedin.com/posts/lilyyue_uxdesign-careerpath-careergrowth-activity-7345798373368578050-6c77?utm_source=social_share_send&amp;utm_medium=member_desktop_web&amp;rcm=ACoAABGhVGkBT-YMeCMZd9fKgSaE_H8BrQil438">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="996"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg"
			
			sizes="100vw"
			alt="A flowchart titled Career Decision Map for UX Designers, put together by Lily Yue"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.linkedin.com/feed/update/urn:li:activity:7345798373368578050/'>A career decision map for UX Designers</a>. Kindly put together by Lily Yue. (<a href='https://files.smashing.media/articles/product-designer-career-paths/1-career-decision-map-ux-designers.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Sometimes these roles might involve acting as a <strong>“translator”</strong> between design and engineering, specializing in UX and accessibility. They could also involve <strong>automating design processes</strong> with AI, improving workflow efficiency, or focusing on internal search UX or legacy systems.</p>

<p>These roles are never advertised, but they have a <strong>tremendous impact</strong> on a business. If you spot such a gap and proactively bring it to senior management, you might be able to shape a role that brings your strengths into the spotlight, rather than trying to fit into a predefined position.</p>

<h2 id="what-about-ai">What About AI?</h2>

<p>One noticeable skill that is worth sharpening is, of course, around <strong>designing AI experiences</strong>. The point isn’t about finding ways to replace design work with AI automation. Today, it seems like people crave nothing more than actual human experience &mdash; created by humans, with attention to humans’ needs and intentions, designed and built and tested with humans, embedding human values and working well for humans.</p>














<figure class="
  
  
  ">
  
    <a href="https://www.linkedin.com/posts/vitalyfriedman_ux-ai-design-activity-7340989532290306051-fLtc/?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAACDcgQBa_vsk5breYKwZAgyIhsHtJaFbL8">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="1017"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg"
			
			sizes="100vw"
			alt="Design Patterns For AI Interfaces, including chatbot widget, inline overlays, infinite canvas, center stage, left panel, right panel."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Design Patterns For AI Interfaces, a quick overview by Sharang Sharma. (<a href='https://files.smashing.media/articles/product-designer-career-paths/6-design-patterns-ai-interfaces.jpeg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>If anything, we should be more <strong>obsessed with humans</strong>, not with AI. If anything, AI amplifies the need for authenticity, curation, critical thinking, and strategy. And that’s a skill that will be very much needed in 2026. We need designers who can design beautiful AI experiences (and frankly, I do have a <a href="https://ai-design-patterns.com/">whole course</a> on that) &mdash; experiences people understand, value, use, and <strong>trust</strong>.</p>

<p>No technology can create <strong>clarity, structure, trust, and care</strong> out of poor content, poor metadata, and poor value for end users. If we understand the fundamentals of good design, and then design with humans in mind, and consider humans’ needs and wants and struggles, we can help users and businesses bridge that gap in a way AI never could. And that’s what you and perhaps your renewed role could bring to the table.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>The most important thing about all these little tools and activities is that they help you <strong>get more clarity</strong>. Clarity on where you currently stand and where you actually want to grow towards.</p>

<p>These are <strong>wonderful conversation starters</strong> to help you find a path you’d love to explore, on your own or with your manager. However, just one thing I’d love to emphasize:</p>

<blockquote>Absolutely, feel free to refine the role to amplify your strengths, rather than finding a way to match a particular role perfectly.</blockquote>

<p>Don’t forget: you bring <strong>incredible value</strong> to your team and to your company. Sometimes it just needs to be highlighted or guided to the right spot to bring it into the spotlight.</p>

<p>You’ve got this &mdash; and happy 2026! ✊🏼✊🏽✊🏾</p>

<h2 id="meet-design-patterns-for-ai-interfaces">Meet “Design Patterns For AI Interfaces”</h2>

<p>Meet <strong>design patterns that work</strong> for AI products in <a href="https://ai-design-patterns.com/"><strong>Design Patterns For AI Interfaces</strong></a>, Vitaly’s shiny new <strong>video course</strong> with practical examples from real-life products &mdash; with a <a href="https://smashingconf.com/online-workshops/workshops/ai-interfaces-vitaly-friedman/">live UX training</a> happening soon. <a href="https://www.youtube.com/watch?v=jhZ3el3n-u0">Jump to a free preview</a>. Use code <strong>SNOWFLAKE</strong> to <strong>save 20%</strong> off!</p>

<p><figure class="break-out article__image" style="margin-bottom: 0"><a href="https://ai-design-patterns.com/"><img style="border-radius:11px" loading="lazy" decoding="async" fetchpriority="low" width="800" height="414" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 400w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 800w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 1200w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 1600w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png 2000w" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/product-designer-career-paths/design-patterns-ai-interfaces.png" sizes="100vw" alt="Design Patterns For AI Interfaces promo picture"></a><figcaption class="op-vertical-bottom">Meet <a href="https://ai-design-patterns.com/">Design Patterns For AI Interfaces</a>, Vitaly’s video course on interface design &amp; UX.</figcaption></figure>
<div class="book-cta__inverted"><div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"><nav class="content-tabs content-tabs--books"><ul><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">
Video + UX Training</button></a></li><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">Video only</button></a></li></ul></nav><div class="book-cta__col book-cta__hardcover content-tab--content"><h3 class="book-cta__title"><span>Video + UX Training</span></h3><span class="book-cta__price"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>450<span class="sup">.00</span></span></span> <span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>799<span class="sup">.00</span></span></span></span></span>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3476562?price_id=4401578" class="btn btn--full btn--medium btn--text-shadow">
Get Video + UX Training<div></div></a><p class="book-cta__desc">30 video lessons (10h) + <a href="https://smashingconf.com/online-workshops/workshops/ai-interfaces-vitaly-friedman/">Live UX Training</a>.<br>100 days money-back-guarantee.</p></div><div class="book-cta__col book-cta__ebook content-tab--content"><h3 class="book-cta__title"><span>Video only</span></h3><div data-audience="anonymous free supporter" data-remove="true"><span class="book-cta__price" data-handler="PriceTag"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>275<span class="sup">.00</span></span></span><span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>395<span class="sup">.00</span></span></span></span></div>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3476562?price_id=4397456" class="btn btn--full btn--medium btn--text-shadow">
Get the video course<div></div></a><p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true">30 video lessons (10h). Updated yearly.<br>Also available as a <a href="https://smart-interface-design-patterns.thinkific.com/enroll/3570306?price_id=4503439">UX Bundle with 3 video courses.</a></p></div><span></span></div></div></p>

<h2 id="useful-resources">Useful Resources</h2>

<ul>
<li><a href="https://www.figma.com/community/file/1142203484282738794/design-skills-matrix">UX Skills Self-Assessment Matrix (Figma template)</a>, by Maigen Thomas</li>
<li>“<a href="https://uxdesign.cc/fixing-product-design-career-paths-with-the-mirror-model-76152b7e547?sk=v2%2F0a6cb162-4def-4f1c-ac5e-b145597646c7">Product Designer’s Career Levels Paths</a>” + <a href="https://drive.google.com/file/d/1BePJyrd8q0D1mVgIV2h8ghds8IbbyzBR/view">PNG</a>, by Ryan Ford</li>
<li><a href="https://www.linkedin.com/feed/update/urn:li:activity:7345798373368578050/">Career Decision Map For UX Designers (PNG)</a>, by Lily Yue</li>
<li><a href="https://www.linkedin.com/posts/lilyyue_uxdesign-careergrowth-productdesign-activity-7343261653901144066-8nLf/">Diverse Career Paths For UX Designers (PNG)</a>, by Lily Yue</li>
<li><a href="https://medium.com/shapingdesign">Shaping Designers and Design Teams</a>, by Jason Mesut</li>
<li><a href="https://miro.com/templates/skills-map-design/">UX Skills Self-Assessment Map template (Miro)</a>, by Paóla Quintero</li>
<li><a href="https://www.nngroup.com/articles/skill-mapping/">UX Skill Mapping Template (Google Sheets)</a>, by Rachel Krause, NN/g</li>
<li>“<a href="https://shannonethomas.com/2023/08/08/growth-framework">Design Team’s Growth Matrix</a>”, by Shannon E. Thomas</li>
<li><a href="https://www.figma.com/community/file/1220482745322443565/figma-product-design-writing-career-levels">Figma Product Design &amp; Writing Career Levels</a>, by Figma</li>
<li><a href="https://miro.com/templates/content-design-role-frameworks/">Content Design Role Frameworks</a>, by Tempo</li>
<li>“<a href="https://dscout.com/people-nerds/uxr-career-framework">UX Research Career Framework</a>”, by Nikki Anderson</li>
<li><a href="https://uxchrisnguyen.gumroad.com/l/uxcareerladder"><em>UX Career Ladders</em> (free eBook)</a>, by Christopher Nguyen</li>
<li><a href="https://docs.google.com/spreadsheets/d/1cNkL4nY3Z8vTyIpIsvqpaFortYZfF-VIoUE0mkbkRMo/edit?gid=0#gid=0">Product Design Level Expectations</a>, by Aaron James</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Vitaly Friedman</author><title>How To Design For (And With) Deaf People</title><link>https://www.smashingmagazine.com/2025/12/how-design-for-with-deaf-people/</link><pubDate>Tue, 30 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/how-design-for-with-deaf-people/</guid><description>Practical UX guidelines to keep in mind for 466 million people who experience hearing loss. More design patterns in &lt;a href="https://smart-interface-design-patterns.com/">Smart Interface Design Patterns&lt;/a>, a &lt;strong>friendly video course on UX&lt;/strong> and design patterns by Vitaly.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/how-design-for-with-deaf-people/" />
              <title>How To Design For (And With) Deaf People</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>How To Design For (And With) Deaf People</h1>
                  
                    
                    <address>Vitaly Friedman</address>
                  
                  <time datetime="2025-12-30T10:00:00&#43;00:00" class="op-published">2025-12-30T10:00:00+00:00</time>
                  <time datetime="2025-12-30T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>When we think about people who are deaf, we often assume stereotypes, such as “disabled” older adults with <strong>hearing aids</strong>. However, this perception is far from the truth and often leads to poor decisions and broken products.</p>

<p>Let’s look at when and how deafness emerges, and how to design better experiences <strong>for people with hearing loss</strong>.</p>














<figure class="
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="783"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg"
			
			sizes="100vw"
			alt="A diagram illustrates sign language with a torso, hands, and blue lines indicating &#39;SPACE&#39; and &#39;TIME,&#39; beside blue text stating &#39;Sign language is four-dimensional."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Sign language is 4-dimensional, including 3D space and time, and often includes facial expressions, too. From a wonderful talk by <a href='https://www.youtube.com/watch?v=M0cR_HTeWUo'>Marie van Driessche</a>. (<a href='https://files.smashing.media/articles/how-design-for-with-deaf-people/1-sign-language.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="deafness-is-a-spectrum">Deafness Is A Spectrum</h2>

<p>Deafness spans a <strong>broad continuum</strong>, from minor to profound hearing loss. Around 90&ndash;95% of deaf people <a href="https://scholarworks.wmich.edu/jssw/vol51/iss1/11/">come from hearing families</a>, and deafness often isn’t merely a condition that people are born with. It frequently occurs due to <strong>exposure to loud noises</strong>, and it also emerges with age, disease, and accidents.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.didyousaydeaf.com/hearing-loss-and-how-hearing-loss-works">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="814"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg"
			
			sizes="100vw"
			alt="A chart showing sound frequencies and decibel levels, illustrating types of hearing loss and common everyday sounds."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      A <a href='https://www.didyousaydeaf.com/hearing-loss-and-how-hearing-loss-works'>chart</a> showing sound frequencies and decibel levels, illustrating types of hearing loss and common everyday sounds. (<a href='https://files.smashing.media/articles/how-design-for-with-deaf-people/2-chart-sound-frequencies-decibel-levels.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The loudness of sound is measured in units called <strong>decibels (dB)</strong>. Everybody is on the <a href="https://www.didyousaydeaf.com/hearing-loss-and-how-hearing-loss-works">spectrum of deafness</a>, from normal hearing (up to 15 dB) to profound hearing loss (91+ dB):</p>

<ul>
<li><strong>Slight Hearing Loss</strong>, 16&ndash;25 dB<br />
At 16 dB hearing loss, a person can miss up to 10% of speech when a speaker is at a distance greater than 3 feet.</li>
<li><strong>Mild hearing loss</strong>, 26&ndash;40 dB<br />
Soft sounds are hard to hear, including whispering, which is around 40 dB in volume. It’s more difficult to hear soft speech sounds spoken at a normal volume. At 40dB hearing loss, a person may miss 50% of meeting discussions.</li>
<li><strong>Moderate hearing loss</strong>, 41&ndash;55 dB<br />
A person may hear almost no speech when another person is talking at normal volume. At a 50dB hearing loss, a person may not pick up to 80% of speech.</li>
<li><strong>Moderately Severe Hearing Loss</strong>, 56&ndash;70 dB<br />
A person may have problems hearing the sounds of a dishwasher (60dB). At 70 dB, they might miss almost all speech.</li>
<li><strong>Severe Hearing Loss</strong>, 71&ndash;90 dB<br />
A person will hear no speech when a person is talking at a normal level. They may hear only some very loud noises: vacuum (70 dB), blender (78 dB), hair dryer (90 dB).</li>
<li><strong>Profound Hearing Loss</strong>, 91+ dB<br />
Hear no speech and at most very loud sounds such as a music player at full volume (100 dB), which would be damaging for people with normal hearing, or a car horn (110 dB).</li>
</ul>

<p>It’s worth mentioning that loss of hearing can also be situational and temporary, as people with “normal” hearing (0 to 25 dB hearing loss) will always encounter situations where they can’t hear, e.g., due to <strong>noisy environments</strong>.</p>

<h2 id="useful-things-to-know-about-deafness">Useful Things To Know About Deafness</h2>

<p>Assumptions are always dangerous, and in the case of deafness, there are quite a few that aren’t accurate. For example, most deaf people actually do not know a sign language &mdash; it’s only around <a href="https://www.accessibility.com/blog/do-all-deaf-people-use-sign-language">1% in the US</a>.</p>

<p>Also, despite our expectations, there is actually <strong>no universal sign language</strong> that everybody uses. For example, British signers often cannot understand American signers. There are globally around <a href="https://education.nationalgeographic.org/resource/sign-language/">300 different sign languages</a> actively used.</p>

<blockquote>“We never question making content available in different written or spoken languages, and the same should apply to signed languages.”<br /><br />&mdash; <a href="https://www.linkedin.com/feed/update/urn:li:activity:7178702360649547778?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7178702360649547778%2C7178776416979718144%29&dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287178776416979718144%2Curn%3Ali%3Aactivity%3A7178702360649547778%29">Johanna Steiner</a></blockquote>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://uxplanet.org/podcasts-for-the-deaf-d4d9b5f3ce99">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="517"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg"
			
			sizes="100vw"
			alt="Three smartphone screens displaying parts of a podcast app, including a browsing page, a now-playing screen with an avatar, and a live transcription feature."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://uxplanet.org/podcasts-for-the-deaf-d4d9b5f3ce99'>Heardio</a> concept: making podcasts accessible for deaf people â€” with live transcription and sign language avatars. (<a href='https://files.smashing.media/articles/how-design-for-with-deaf-people/3-heardio.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Sign languages are <a href="https://www.youtube.com/watch?v=M0cR_HTeWUo&amp;t=188">not just gestures or pantomime</a>. They are <strong>4D spatial languages</strong> with their own grammar and syntax, separate from spoken languages, and they don’t have a written form. They rely heavily on facial expression to convey meaning and emphasis. And they are also not universal &mdash; every country has its own sign language and dialects.</p>

<ul>
<li>You can only understand <strong>30% of words</strong> via lip-reading.</li>
<li>Most deaf people do not know any <strong>sign language</strong>.</li>
<li>Many sign languages have local dialects that can be hard to interpret.</li>
<li>Not all deaf people are fluent signers and often rely on <strong>visual clues</strong>.</li>
<li>For many deaf people, a spoken language is their <strong>second language</strong>.</li>
<li><a href="https://www.youtube.com/watch?v=M0cR_HTeWUo"><strong>Sign language is 4-dimensional</strong></a>, incorporating 3D space, time and also facial expressions.</li>
</ul>

<h2 id="how-to-communicate-respectfully">How To Communicate Respectfully</h2>

<p>Keep in mind that many deaf people use the spoken language of their country as <strong>their second language</strong>. So to communicate with a deaf person, it’s best to ask in writing. Don’t ask how much a person can understand, or if they can lip-read you.</p>

<p>However, as Rachel Edwards <a href="https://www.linkedin.com/posts/rachel-edwards-scotland_excellent-overview-on-designing-for-ddeaf-activity-7409172866983804928-489h?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAACDcgQBa_vsk5breYKwZAgyIhsHtJaFbL8">noted</a>, don’t assume someone is comfortable with written language because they are deaf. Sometimes their literacy may be low, and so providing information as text and assuming that covers your deaf users might not be the answer.</p>

<p>Also, don’t assume that every deaf person can lip-read. You can see only about 30% of words on someone’s mouth. That’s why many deaf people need <strong>additional visual cues</strong>, like text or cued speech.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.healthyhearing.com/report/52264-Universal-signs-for-hearing-loss">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="675"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png"
			
			sizes="100vw"
			alt="Seven accessibility symbols for people with hearing loss are displayed: International Symbol of Access, assistive listening devices, telephone typewriter, volume control telephone, sign language interpretation, closed captioning, and open captioning."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      7 accessibility symbols for people with hearing loss. <a href='https://www.healthyhearing.com/report/52264-Universal-signs-for-hearing-loss'>Universal signs for hearing loss</a>. (<a href='https://files.smashing.media/articles/how-design-for-with-deaf-people/4-accessibility-symbols.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>It’s also crucial to use <strong>respectful language</strong>. Deaf people do not always see themselves as <em>disabled</em>, but rather as a cultural linguistic minority with a unique identity. Others, as Meryl Evan has <a href="https://www.linkedin.com/feed/update/urn:li:activity:7178702360649547778?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7178702360649547778%2C7178721132345270272%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287178721132345270272%2Curn%3Ali%3Aactivity%3A7178702360649547778%29">noted</a>, don’t identify as <em>deaf</em> or <em>hard of hearing</em>, but rather as “hearing impaired”. So, it’s mostly up to an individual how they want to identify.</p>

<ul>
<li><strong>Deaf</strong> (Capital ‘D’)<br />
Culturally Deaf people who have been deaf since birth or before learning to speak. Sign language is often the first language, and written language is the second.</li>
<li><strong>deaf</strong> (Lowercase ‘d’)<br />
People who developed hearing loss later in life. Used by people who feel closer to the hearing/hard-of-hearing world and prefer to communicate written and/or oral.</li>
<li><strong>Hard of Hearing</strong><br />
People with mild to moderate hearing loss who typically communicate orally and use hearing aids.</li>
</ul>

<p>In general, <strong>avoid hearing impairment</strong> if you can, and use <em>Deaf</em> (for those deaf for most of their lives), <em>deaf</em> (for those who became deaf later), or <em>hard of hearing</em> (HoH) for partial hearing loss. But either way, ask politely first and then respect the person’s preferences.</p>

<h2 id="practical-ux-guidelines">Practical UX Guidelines</h2>

<p>When designing UIs and content, consider these key accessibility guidelines for deaf and hard-of-hearing users:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://prospect.org.uk/article/designing-content-for-users-who-are-deaf-or-hard-of-hearing/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg"
			
			sizes="100vw"
			alt="An infographic on a teal background titled &#39;Designing for users who are deaf or hard of hearing,&#39; listing &#39;Do&#39;s and Don&#39;ts&#39; with icons."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      How to design for users who are deaf or hard of hearing, a Gov.uk-inspired poster by <a href='https://prospect.org.uk/article/designing-content-for-users-who-are-deaf-or-hard-of-hearing/'>Prospect.org.uk</a>. <a href='https://d28j9ucj9uj44t.cloudfront.net/uploads/2021/09/Designing_for_accessibility6.pdf'>Download a printable PDF</a>. (<a href='https://files.smashing.media/articles/how-design-for-with-deaf-people/5-designing-deaf-users.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<ol>
<li><strong>Don’t make the phone required</strong> or the only method of contact.</li>
<li><strong>Provide text alternatives</strong> for all audible alerts or notices.</li>
<li><strong>Add haptic feedback</strong> on mobile (e.g., vibration patterns).</li>
<li><strong>Ensure good lighting</strong> to help people see facial expressions.</li>
<li><strong>Circular seating</strong> usually works better, so everyone can see each other’s faces.</li>
<li><strong>Always include descriptions of non-spoken sounds</strong> (e.g., rain, laughter) in your content.</li>
<li><strong>Add a transcript and closed captions</strong> for audio and video.</li>
<li><strong>Clearly identify each speaker</strong> in all audio and video content.</li>
<li><strong>Design multiple ways to communicate</strong> in every instance (online + in-person).</li>
<li><strong>Invite video participants to keep the camera on</strong> to facilitate lip-reading and the viewing of facial expressions, which convey tone.</li>
<li><strong>Always test products with the actual community</strong>, instead of making assumptions for them.</li>
</ol>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>I keep repeating myself like a broken record, but better accessibility <strong>always benefits everyone</strong>. When we improve experiences for some groups of people, it often improves experiences for entirely different groups as well.</p>

<p>As Marie Van Driessche rightfully noted, to design a great experience for accessibility, we must design <strong>with</strong> people, rather than <em>for</em> them. And that means always include people with <strong>lived experience of exclusion</strong> into the design process &mdash; as they are the true experts.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aAccessibility%20never%20happens%20by%20accident%20%e2%80%94%20it%e2%80%99s%20a%20deliberate%20decision%20and%20a%20commitment.%0a&url=https://smashingmagazine.com%2f2025%2f12%2fhow-design-for-with-deaf-people%2f">
      
Accessibility never happens by accident — it’s a deliberate decision and a commitment.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>No digital product is neutral. There must be a deliberate effort to make products and services more accessible. Not only does it benefit everyone, but it also shows what a company stands for and values.</p>

<p>And once you do have a commitment, it will be so much easier to <strong>retain accessibility</strong> rather than adding it last minute as a crutch &mdash; when it’s already too late to do it right and way too expensive to do it well.</p>

<h2 id="meet-smart-interface-design-patterns">Meet “Smart Interface Design Patterns”</h2>

<p>You can find more details on <strong>design patterns and UX</strong> in <a href="https://smart-interface-design-patterns.com/"><strong>Smart Interface Design Patterns</strong></a>, our <strong>15h-video course</strong> with 100s of practical examples from real-life projects &mdash; with a live UX training later this year. Everything from mega-dropdowns to complex enterprise tables &mdash; with 5 new segments added every year. <a href="https://www.youtube.com/watch?v=jhZ3el3n-u0">Jump to a free preview</a>. Use code <a href="https://smart-interface-design-patterns.com"><strong>BIRDIE</strong></a> to <strong>save 15%</strong> off.</p>

<figure style="margin-bottom: 0"><a href="https://smart-interface-design-patterns.com/"><img style="border-radius: 11px" decoding="async" fetchpriority="low" width="950" height="492" srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg 400w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg 800w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg 1200w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg 1600w,
https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg 2000w" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7cc4e1de-6921-474e-a3fb-db4789fc13dd/b4024b60-e627-177d-8bff-28441f810462.jpeg" sizes="100vw" alt="Smart Interface Design Patterns"></a><figcaption class="op-vertical-bottom">Meet <a href="https://smart-interface-design-patterns.com/">Smart Interface Design Patterns</a>, our video course on interface design &amp; UX.</figcaption></figure>

<div class="book-cta__inverted"><div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"><nav class="content-tabs content-tabs--books"><ul><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">
Video + UX Training</button></a></li><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">Video only</button></a></li></ul></nav><div class="book-cta__col book-cta__hardcover content-tab--content"><h3 class="book-cta__title"><span>Video + UX Training</span></h3><span class="book-cta__price"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>495<span class="sup">.00</span></span></span> <span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>699<span class="sup">.00</span></span></span></span></span>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3951439" class="btn btn--full btn--medium btn--text-shadow">
Get Video + UX Training<div></div></a><p class="book-cta__desc">25 video lessons (15h) + <a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/">Live UX Training</a>.<br>100 days money-back-guarantee.</p></div><div class="book-cta__col book-cta__ebook content-tab--content"><h3 class="book-cta__title"><span>Video only</span></h3><div data-audience="anonymous free supporter" data-remove="true"><span class="book-cta__price" data-handler="PriceTag"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>300<span class="sup">.00</span></span></span><span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>395<span class="sup">.00</span></span></span></span></div>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3950630" class="btn btn--full btn--medium btn--text-shadow">
Get the video course<div></div></a><p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true">40 video lessons (15h). Updated yearly.<br>Also available as a <a href="https://smart-interface-design-patterns.thinkific.com/enroll/3082557?price_id=3951421">UX Bundle with 2 video courses.</a></p></div><span></span></div></div>

<h2 id="useful-resources">Useful Resources</h2>

<ul>
<li><a href="https://www.youtube.com/watch?v=M0cR_HTeWUo">Designing For Deaf People Helps Everyone</a>, by Marie Van Driessche</li>
<li>“<a href="https://medium.com/@paulrobwest/ux-ui-design-considerations-for-the-deaf-deaf-and-hard-of-hearing-dbfe28850fbe">Design considerations for the Deaf, deaf, and hard of hearing</a>”, by Paul Roberts</li>
<li><a href="https://www.youtube.com/watch?v=AEXKOASrTVM">Beyond Video Captions and Sign Language</a>, by Svetlana Kouznetsova</li>
<li>“<a href="https://www.smashingmagazine.com/2023/01/closed-captions-subtitles-ux/">Best Practices For CC and Subtitles UX</a>”, by Vitaly Friedman</li>
<li><a href="https://www.accessi.org/blog/web-accessibility-for-deaf-users/">Web Accessibility for Deaf Users</a></li>
<li><a href="https://www.inclusivedesigntoolkit.com/UChearing/hearing.html">Inclusive Design Toolkit: Hearing</a></li>
<li>“<a href="https://funkybrownchick.substack.com/p/i-hear-you-really-i-do-">What It&rsquo;s Like To Be Born Hard of Hearing</a>”, by Twanna A. Hines, M.S.</li>
<li>“<a href="https://uxplanet.org/podcasts-for-the-deaf-d4d9b5f3ce99">Accessibility: Podcasts for the deaf</a>”, by Mubarak Alabidun</li>
</ul>

<h3 id="useful-books">Useful Books</h3>

<ul>
<li><a href="https://audio-accessibility.com/book/"><em>Sound Is Not Enough</em></a>, by Svetlana Kouznetsova</li>
<li><em>Mismatch: How Inclusion Shapes Design</em>, by Kat Holmes</li>
<li><em>Building for Everyone: Extend Your Product&rsquo;s Reach Through Inclusive Design</em> (+ <a href="https://design.google/library/building-for-everyone">free excerpt</a>), by Annie Jean-Baptiste</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Paul Boag</author><title>Giving Users A Voice Through Virtual Personas</title><link>https://www.smashingmagazine.com/2025/12/giving-users-voice-virtual-personas/</link><pubDate>Tue, 23 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/giving-users-voice-virtual-personas/</guid><description>Turn scattered user research into AI-powered personas that give anyone consolidated multi-perspective feedback from a single question.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/giving-users-voice-virtual-personas/" />
              <title>Giving Users A Voice Through Virtual Personas</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Giving Users A Voice Through Virtual Personas</h1>
                  
                    
                    <address>Paul Boag</address>
                  
                  <time datetime="2025-12-23T10:00:00&#43;00:00" class="op-published">2025-12-23T10:00:00+00:00</time>
                  <time datetime="2025-12-23T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>In my <a href="https://www.smashingmagazine.com/2025/09/functional-personas-ai-lean-practical-workflow/">previous article</a>, I explored how AI can help us create functional personas more efficiently. We looked at building personas that focus on what users are trying to accomplish rather than demographic profiles that look good on posters but rarely change design decisions.</p>

<p>But creating personas is only half the battle. The bigger challenge is getting those insights into the hands of people who need them, at the moment they need them.</p>

<p>Every day, people across your organization make decisions that affect user experience. Product teams decide which features to prioritize. Marketing teams craft campaigns. Finance teams design invoicing processes. Customer support teams write response templates. All of these decisions shape how users experience your product or service.</p>

<p>And most of them happen without any input from actual users.</p>

<h2 id="the-problem-with-how-we-share-user-research">The Problem With How We Share User Research</h2>

<p>You do the research. You create the personas. You write the reports. You give the presentations. You even make fancy infographics. And then what happens?</p>

<p>The research sits in a shared drive somewhere, slowly gathering digital dust. The personas get referenced in kickoff meetings and then forgotten. The reports get skimmed once and never opened again.</p>

<p>When a product manager is deciding whether to add a new feature, they probably do not dig through last year’s research repository. When the finance team is redesigning the invoice email, they almost certainly do not consult the user personas. They make their best guess and move on.</p>

<p>This is not a criticism of those teams. They are busy. They have deadlines. And honestly, even if they wanted to consult the research, they probably would not know where to find it or how to interpret it for their specific question.</p>

<p>The knowledge stays locked inside the heads of the UX team, who cannot possibly be present for every decision being made across the organization.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="what-if-users-could-actually-speak">What If Users Could Actually Speak?</h2>

<blockquote>What if, instead of creating static documents that people need to find and interpret, we could give stakeholders a way to consult all of your user personas at once?</blockquote>

<p>Imagine a marketing manager working on a new campaign. Instead of trying to remember what the personas said about messaging preferences, they could simply ask: <em>“I’m thinking about leading with a discount offer in this email. What would our users think?”</em></p>

<p>And the AI, drawing on all your research data and personas, could respond with a consolidated view: how each persona would likely react, where they agree, where they differ, and a set of recommendations based on their collective perspectives. One question, synthesized insight across your entire user base.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="496"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png"
			
			sizes="100vw"
			alt="Personas"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      You can question how personas will react to different scenarios based on the research available. (<a href='https://files.smashing.media/articles/giving-users-voice-virtual-personas/1-user-research-personas.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>This is not science fiction. With AI, we can build exactly this kind of system. We can take all of that scattered research (the surveys, the interviews, the support tickets, the analytics, the personas themselves) and turn it into an <strong>interactive resource</strong> that anyone can query for multi-perspective feedback.</p>

<h2 id="building-the-user-research-repository">Building the User Research Repository</h2>

<p>The foundation of this approach is a centralized repository of everything you know about your users. Think of it as a single source of truth that AI can access and draw from.</p>

<p>If you have been doing user research for any length of time, you probably have more data than you realize. It is just scattered across different tools and formats:</p>

<ul>
<li>Survey results sitting in your survey platform,</li>
<li>Interview transcripts in Google Docs,</li>
<li>Customer support tickets in your helpdesk system,</li>
<li>Analytics data in various dashboards,</li>
<li>Social media mentions and reviews,</li>
<li>Old personas from previous projects,</li>
<li>Usability test recordings and notes.</li>
</ul>

<p>The first step is gathering all of this into one place. It does not need to be perfectly organized. AI is remarkably good at making sense of messy inputs.</p>

<p>If you are starting from scratch and do not have much existing research, you can use AI deep research tools to establish a baseline.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="599"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png"
			
			sizes="100vw"
			alt="Research with perplexity"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Online deep research with a tool like perplexity can be invaluable as a starting point for user research. (<a href='https://files.smashing.media/articles/giving-users-voice-virtual-personas/2-user-research-perplexity.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>These tools can scan the web for discussions about your product category, competitor reviews, and common questions people ask. This gives you something to work with while you build out your primary research.</p>

<h2 id="creating-interactive-personas">Creating Interactive Personas</h2>

<p>Once you have your repository, the next step is creating personas that the AI can consult on behalf of stakeholders. This builds directly on <a href="https://www.smashingmagazine.com/2025/09/functional-personas-ai-lean-practical-workflow/">the functional persona approach I outlined in my previous article</a>, with one key difference: these personas become <strong>lenses</strong> through which the AI analyzes questions, not just reference documents.</p>

<p>The process works like this:</p>

<ol>
<li>Feed your research repository to an AI tool.</li>
<li>Ask it to identify distinct user segments based on goals, tasks, and friction points.</li>
<li>Have it generate detailed personas for each segment.</li>
<li>Configure the AI to consult all personas when stakeholders ask questions, providing consolidated feedback.</li>
</ol>

<p>Here is where this approach diverges significantly from traditional personas. Because the AI is the primary consumer of these persona documents, they do not need to be scannable or fit on a single page. Traditional personas are constrained by human readability: you have to distill everything down to bullet points and key quotes that someone can absorb at a glance. But AI has no such limitation.</p>

<p>This means your personas can be considerably <strong>more detailed</strong>. You can include lengthy behavioral observations, contradictory data points, and nuanced context that would never survive the editing process for a traditional persona poster. The AI can hold all of this complexity and draw on it when answering questions.</p>

<p>You can also create <strong>different lenses or perspectives within each persona</strong>, tailored to specific business functions. Your “Weekend Warrior” persona might have a marketing lens (messaging preferences, channel habits, campaign responses), a product lens (feature priorities, usability patterns, upgrade triggers), and a support lens (common questions, frustration points, resolution preferences). When a marketing manager asks a question, the AI draws on the marketing-relevant information. When a product manager asks, it pulls from the product lens. Same persona, different depth depending on who is asking.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="568"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png"
			
			sizes="100vw"
			alt="Persona Lenses"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Personas can have different lenses relevant to different functions within the business. (<a href='https://files.smashing.media/articles/giving-users-voice-virtual-personas/3-persona-lenses.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The personas should still include all the functional elements we discussed before: goals and tasks, questions and objections, pain points, touchpoints, and service gaps. But now these elements become the basis for how the AI evaluates questions from each persona’s perspective, synthesizing their views into actionable recommendations.</p>

<div class="partners__lead-place"></div>

<h2 id="implementation-options">Implementation Options</h2>

<p>You can set this up with varying levels of sophistication depending on your resources and needs.</p>

<h3 id="the-simple-approach">The Simple Approach</h3>

<p>Most AI platforms now offer project or workspace features that let you upload reference documents. In ChatGPT, these are called Projects. Claude has a similar feature. Copilot and Gemini call them Spaces or Gems.</p>

<p>To get started, create a dedicated project and upload your key research documents and personas. Then write clear instructions telling the AI to consult all personas when responding to questions. Something like:</p>

<blockquote>You are helping stakeholders understand our users. When asked questions, consult all of the user personas in this project and provide: (1) a brief summary of how each persona would likely respond, (2) an overview highlighting where they agree and where they differ, and (3) recommendations based on their collective perspectives. Draw on all the research documents to inform your analysis. If the research does not fully cover a topic, search social platforms like Reddit, Twitter, and relevant forums to see how people matching these personas discuss similar issues. If you are still unsure about something, say so honestly and suggest what additional research might help.</blockquote>

<p>This approach has some limitations. There are caps on how many files you can upload, so you might need to prioritize your most important research or consolidate your personas into a single comprehensive document.</p>

<h3 id="the-more-sophisticated-approach">The More Sophisticated Approach</h3>

<p>For larger organizations or more ongoing use, a tool like <a href="https://www.notion.com/">Notion</a> offers advantages because it can hold your entire <strong>research repository</strong> and has AI capabilities built in. You can create databases for different types of research, link them together, and then use the AI to query across everything.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="599"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png"
			
			sizes="100vw"
			alt="Notion homepage"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Notion is a powerful tool for user research with built-in AI functionality that can refer to all your personas as well as your entire research repository. (<a href='https://files.smashing.media/articles/giving-users-voice-virtual-personas/4-notion-user-research.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The benefit here is that the AI has access to much <strong>more context</strong>. When a stakeholder asks a question, it can draw on surveys, support tickets, interview transcripts, and analytics data all at once. This makes for richer, more nuanced responses.</p>

<h2 id="what-this-does-not-replace">What This Does Not Replace</h2>

<p>I should be clear about the limitations.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aVirtual%20personas%20are%20not%20a%20substitute%20for%20talking%20to%20real%20users.%20They%20are%20a%20way%20to%20make%20existing%20research%20more%20accessible%20and%20actionable.%0a&url=https://smashingmagazine.com%2f2025%2f12%2fgiving-users-voice-virtual-personas%2f">
      
Virtual personas are not a substitute for talking to real users. They are a way to make existing research more accessible and actionable.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>There are several scenarios where you still need primary research:</p>

<ul>
<li>When launching something genuinely new that your existing research does not cover;</li>
<li>When you need to validate specific designs or prototypes;</li>
<li>When your repository data is getting stale;</li>
<li>When stakeholders need to hear directly from real humans to build empathy.</li>
</ul>

<p>In fact, you can configure the AI to recognize these situations. When someone asks a question that goes beyond what the research can answer, the AI can respond with something like: <em>“I do not have enough information to answer that confidently. This might be a good question for a quick user interview or survey.”</em></p>

<p>And when you do conduct new research, that data feeds back into the repository. The personas evolve over time as your understanding deepens. This is much better than the traditional approach, where personas get created once and then slowly drift out of date.</p>

<div class="partners__lead-place"></div>

<h2 id="the-organizational-shift">The Organizational Shift</h2>

<p>If this approach catches on in your organization, something interesting happens.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aThe%20UX%20team%e2%80%99s%20role%20shifts%20from%20being%20the%20gatekeepers%20of%20user%20knowledge%20to%20being%20the%20curators%20and%20maintainers%20of%20the%20repository.%0a&url=https://smashingmagazine.com%2f2025%2f12%2fgiving-users-voice-virtual-personas%2f">
      
The UX team’s role shifts from being the gatekeepers of user knowledge to being the curators and maintainers of the repository.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>Instead of spending time creating reports that may or may not get read, you spend time ensuring the repository stays current and that the AI is configured to give helpful responses.</p>

<p>Research communication changes from push (presentations, reports, emails) to pull (stakeholders asking questions when they need answers). <strong>User-centered thinking</strong> becomes distributed across the organization rather than concentrated in one team.</p>

<p>This does not make UX researchers less valuable. If anything, it makes them more valuable because their work now has a wider reach and greater impact. But it does change the nature of the work.</p>

<h2 id="getting-started">Getting Started</h2>

<p>If you want to try this approach, start small. If you need a primer on functional personas before diving in, I have written a <a href="https://boagworld.com/usability/personas/">detailed guide to creating them</a>. Pick one project or team and set up a simple implementation using ChatGPT Projects or a similar tool. Gather whatever research you have (even if it feels incomplete), create one or two personas, and see how stakeholders respond.</p>

<p>Pay attention to what questions they ask. These will tell you where your research has gaps and what additional data would be most valuable.</p>

<p>As you refine the approach, you can expand to more teams and more sophisticated tooling. But the core principle stays the same: <strong>take all that scattered user knowledge and give it a voice that anyone in your organization can hear.</strong></p>

<p>In my previous article, I argued that we should move from demographic personas to functional personas that focus on what users are trying to do. Now I am suggesting we take the next step: from static personas to interactive ones that can actually participate in the conversations where decisions get made.</p>

<p>Because every day, across your organization, people are making decisions that affect your users. And your users deserve a seat at the table, even if it is a virtual one.</p>

<h3 id="further-reading-on-smashingmag">Further Reading On SmashingMag</h3>

<ul>
<li>“<a href="https://www.smashingmagazine.com/2014/08/a-closer-look-at-personas-part-1/">A Closer Look At Personas: What They Are And How They Work | 1</a>”, Shlomo Goltz</li>
<li>“<a href="https://www.smashingmagazine.com/2018/04/design-process-data-based-personas/">How To Improve Your Design Process With Data-Based Personas</a>”, Tim Noetzel</li>
<li>“<a href="https://www.smashingmagazine.com/2025/10/how-make-ux-research-hard-to-ignore/">How To Make Your UX Research Hard To Ignore</a>”, Vitaly Friedman</li>
<li>“<a href="https://www.smashingmagazine.com/2023/01/build-strong-customer-relationships-user-research/">How To Build Strong Customer Relationships For User Research</a>”, Renaissance Rachel</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Vitaly Friedman</author><title>How To Measure The Impact Of Features</title><link>https://www.smashingmagazine.com/2025/12/how-measure-impact-features-tars/</link><pubDate>Fri, 19 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/how-measure-impact-features-tars/</guid><description>Meet TARS — a simple, repeatable, and meaningful UX metric designed specifically to track the performance of product features. Upcoming part of the &lt;a href="https://measure-ux.com/">Measure UX &amp;amp; Design Impact&lt;/a> (use the code 🎟 &lt;code>IMPACT&lt;/code> to save 20% off today).</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/how-measure-impact-features-tars/" />
              <title>How To Measure The Impact Of Features</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>How To Measure The Impact Of Features</h1>
                  
                    
                    <address>Vitaly Friedman</address>
                  
                  <time datetime="2025-12-19T10:00:00&#43;00:00" class="op-published">2025-12-19T10:00:00+00:00</time>
                  <time datetime="2025-12-19T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>So we design and ship a <strong>shiny new feature</strong>. How do we know if it’s working? How do we measure and track its impact? There is <a href="https://measuringu.com/an-overview-of-70-ux-metrics/">no shortage in UX metrics</a>, but what if we wanted to establish a <strong>simple, repeatable</strong>, meaningful UX metric &mdash; specifically for our features? Well, let’s see how to do just that.</p>














<figure class="
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="975"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="Adrian Raudaschl&#39;s framework for measuring feature impact."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      With <a href='https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a?sk=v2%2F2a9d7d1e-bae9-4875-9063-4b6a10ae110c'>TARS</a>, we can assess how effective features are and how well they are performing.(<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/1-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I first heard about the <strong>TARS framework</strong> from Adrian H. Raudschl’s wonderful article on “<a href="https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a?sk=v2%2F2a9d7d1e-bae9-4875-9063-4b6a10ae110c">How To Measure Impact of Features</a>”. Here, Adrian highlighted how his team tracks and decides which features to focus on &mdash; and then maps them against each other in a <strong>2×2 quadrants matrix</strong>.</p>

<p>It turned out to be a very useful framework to <strong>visualize</strong> the impact of UX work through the lens of business metrics.</p>

<p>Let’s see how it works.</p>

<h2 id="1-target-audience">1. Target Audience (%)</h2>

<p>We start by quantifying the <strong>target audience</strong> by exploring what percentage of a product’s users have the specific problem that a feature aims to solve. We can study existing or similar features that try to solve similar problems, and how many users engage with them.</p>

<p>Target audience <strong>isn’t the same</strong> as feature usage though. As Adrian noted, if we know that an existing Export Button feature is used by 5% of all users, it doesn’t mean that the target audience is 5%. <strong>More users</strong> might have the problem that the export feature is trying to solve, but they can’t find it.</p>

<blockquote>Question we ask: “What percentage of all our product’s users have that specific problem that a new feature aims to solve?”</blockquote>

<h2 id="2-a-adoption">2. A = Adoption (%)</h2>

<p>Next, we measure how well we are <strong>“acquiring”</strong> our target audience. For that, we track how many users actually engage <em>successfully</em> with that feature over a specific period of time.</p>

<p>We <strong>don’t focus on CTRs or session duration</strong> there, but rather if users <em>meaningfully</em> engage with it. For example, if anything signals that they found it valuable, such as sharing the export URL, the number of exported files, or the usage of filters and settings.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="395"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="The TARS Framework Step"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Adoption rates: from low adoption (<20%) to high adoption (>60%). Illustration by <a href='https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a?sk=v2%2F2a9d7d1e-bae9-4875-9063-4b6a10ae110c'>Adrian Raudaschl</a>. (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/2-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>High <strong>feature adoption</strong> (&gt;60%) suggests that the problem was impactful. Low adoption (&lt;20%) might imply that the problem has simple workarounds that people have relied upon. Changing habits takes time, too, and so low adoption in the beginning is expected.</p>

<p>Sometimes, low feature adoption has nothing to do with the feature itself, but rather <strong>where it sits in the UI</strong>. Users might never discover it if it’s hidden or if it has a confusing label. It must be obvious enough for people to stumble upon it.</p>

<p>Low adoption doesn’t always equal failure. If a problem only affects 10% of users, hitting 50–75% adoption within that specific niche means the feature is a <strong>success</strong>.</p>

<blockquote>Question we ask: “What percentage of active target users actually use the feature to solve that problem?”</blockquote>

<h2 id="3-retention">3. Retention (%)</h2>

<p>Next, we study whether a feature is actually used repeatedly. We measure the frequency of use, or specifically, how many users who engaged with the feature actually keep using it over time. Typically, it’s a strong signal for <strong>meaningful impact</strong>.</p>

<p>If a feature has &gt;50% retention rate (avg.), we can be quite confident that it has a <strong>high strategic importance</strong>. A 25–35% retention rate signals medium strategic significance, and retention of 10–20% is then low strategic importance.</p>

<blockquote>Question we ask: “Of all the users who meaningfully adopted a feature, how many came back to use it again?”</blockquote>

<h2 id="4-satisfaction-score-ces">4. Satisfaction Score (CES)</h2>

<p>Finally, we measure the <strong>level of satisfaction</strong> that users have with that feature that we’ve shipped. We don’t ask everyone &mdash; we ask only “retained” users. It helps us spot hidden troubles that might not be reflected in the retention score.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="395"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="Customer Satisfaction Score, measured with a survey"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      We ask users how easy it was to solve a problem after they used a feature. Illustration by <a href='https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a?sk=v2%2F2a9d7d1e-bae9-4875-9063-4b6a10ae110c'>Adrian Raudaschl</a>. (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/3-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Once users actually used a feature multiple times, we ask them <strong>how easy it was to solve</strong> a problem after they used that feature &mdash; between “much more difficult” and “much easier than expected”. We know how we want to score.</p>

<h2 id="using-tars-for-feature-strategy">Using TARS For Feature Strategy</h2>

<p>Once we start measuring with TARS, we can calculate an <strong>S÷T score</strong> &mdash; the percentage of Satisfied Users ÷ Target Users. It gives us a sense of how well a feature is performing for our intended target audience. Once we do that for every feature, we can map all features across 4 quadrants in a <strong>2×2 matrix</strong>.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="400"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="Feature retention curves"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Evaluating features on a 2×2 matrix based on S/T score Illustration by <a href='https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a?sk=v2%2F2a9d7d1e-bae9-4875-9063-4b6a10ae110c'>Adrian Raudaschl</a>. (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/4-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p><strong>Overperforming features</strong> are worth paying attention to: they have low retention but high satisfaction. It might simply be features that users don’t have to use frequently, but when they do, it’s extremely effective.</p>

<p><strong>Liability features</strong> have high retention but low satisfaction, so perhaps we need to work on them to improve them. And then we can also identify <strong>core features</strong> and project features &mdash; and have a conversation with designers, PMs, and engineers on what we should work on next.</p>

<div class="partners__lead-place"></div>

<h2 id="conversion-rate-is-not-a-ux-metric">Conversion Rate Is Not a UX Metric</h2>

<p>TARS doesn’t cover conversion rate, and for a good reason. As <a href="https://www.linkedin.com/posts/fabian-lenz-digital-experience-leadership_conversion-rate-is-not-a-ux-metric-yes-activity-7394261839506739200-78G9">Fabian Lenz noted</a>, conversion is often considered to be the <strong>ultimate indicator of success</strong> &mdash; yet in practice it’s always very difficult to present a clear connection between smaller design initiatives and big conversion goals.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="274"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png"
			
			sizes="100vw"
			alt="Chart comparing Leading vs Lagging Measures for UX metrics"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Leading vs. Lagging Measures by <a href='https://measuringu.com/leading-vs-lagging/'>Jeff Sauro and James R. Lewis</a>. (But please do avoid NPS at all costs). (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/5-impact-features-tars.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The truth is that almost everybody on the team is working towards better conversion. An uptick might be connected to <strong>many different initiatives</strong> &mdash; from sales and marketing to web performance boost to seasonal effects to UX initiatives.</p>

<p>UX can, of course, improve conversion, but it’s not really a UX metric. Often, people simply <strong>can’t choose the product</strong> they are using. And often a desired business outcome comes out of necessity and struggle, rather than trust and appreciation.</p>

<h3 id="high-conversion-despite-bad-ux">High Conversion Despite Bad UX</h3>

<p>As Fabian <a href="https://www.linkedin.com/posts/fabian-lenz-digital-experience-leadership_conversion-rate-is-not-a-ux-metric-yes-activity-7394261839506739200-78G9/">writes</a>, <strong>high conversion rate</strong> can happen despite poor UX, because:</p>

<ul>
<li><strong>Strong brand power</strong> pulls people in,</li>
<li>Aggressive but effective <strong>urgency tactics</strong>,</li>
<li>Prices are extremely attractive,</li>
<li>Marketing performs brilliantly,</li>
<li>Historical customer loyalty,</li>
<li>Users simply have no alternative.</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="509"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="UX Scorecard and design metrics overview"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      A practical overview of design metrics and UX scorecards: <a href='https://uxplanet.org/measuring-ux-your-first-step-towards-objective-evaluation-a408b312777b'>Measuring UX: Your First Step Towards Objective Evaluation</a> by Roman Videnov. (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/6-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<h3 id="low-conversion-despite-great-ux">Low Conversion Despite Great UX</h3>

<p>At the same time, a low conversion rate can occur despite great UX, because:</p>

<ul>
<li><strong>Offers aren’t relevant</strong> to the audience,</li>
<li><strong>Users don’t trust the brand</strong>,</li>
<li>Poor business model or high risk of failure,</li>
<li>Marketing doesn’t reach the right audience,</li>
<li>External factors (price, timing, competition).</li>
</ul>

<p>An improved conversion is the <strong>positive outcome of UX initiatives</strong>. But good UX work typically improves task completion, reduces time on task, minimizes errors, and avoids decision paralysis. And there are plenty of <a href="https://www.linkedin.com/posts/vitalyfriedman_how-to-measure-ux-httpslnkdine5uedtzy-activity-7332664809382952960-HERA">actionable design metrics we could use</a> to track UX and drive sustainable success.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p><strong>Product metrics</strong> alone don’t always provide an accurate view of how well a product performs. Sales might perform well, but users might be extremely inefficient and frustrated. Yet the churn is low because users can’t choose the tool they are using.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg"
			
			sizes="100vw"
			alt="Chart comparing Leading vs Lagging Measures for UX metrics"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.linkedin.com/posts/vitalyfriedman_ux-design-activity-7140641630507687936-YTI7'>Design KPIs and UX Metrics</a>, a quick overview by yours truly. Numbers are, of course, placeholders. (<a href='https://files.smashing.media/articles/how-measure-impact-features-tars/7-impact-features-tars.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>We need UX metrics to understand and improve user experience. What I love most about TARS is that it’s a neat way to connect customers’ usage and <strong>customers’ experience with relevant product metrics</strong>. Personally, I would extend TARS with <a href="https://www.linkedin.com/posts/vitalyfriedman_ux-design-activity-7140641630507687936-YTI7">UX-focused metrics and KPIs</a> as well &mdash; depending on the needs of the project.</p>

<p>Huge thanks to <a href="https://www.linkedin.com/in/adrian-raudaschl/">Adrian H. Raudaschl</a> for putting it together. And if you are interested in metrics, I highly recommend you follow him for practical and useful guides all around just that!</p>

<h2 id="meet-how-to-measure-ux-and-design-impact">Meet “How To Measure UX And Design Impact”</h2>

<p>You can find more details on <strong>UX Strategy</strong> in 🪴&nbsp;<a href="https://measure-ux.com/"><strong>Measure UX &amp; Design Impact</strong></a> (8h), a practical guide for designers and UX leads to measure and show your UX impact on business. Use the code 🎟 <code>IMPACT</code> to save 20% off today. <a href="https://measure-ux.com/">Jump to the details</a>.</p>

<figure style="margin-bottom:0;padding-bottom:0" class="article__image">
    <a href="https://measure-ux.com/" title="How To Measure UX and Design Impact, with Vitaly Friedman">
    <img width="900" height="466" style="border-radius: 11px" src="https://files.smashing.media/articles/ux-metrics-video-course-release/measure-ux-and-design-impact-course.png" alt="How to Measure UX and Design Impact, with Vitaly Friedman.">
    </a>
</figure>

<div class="book-cta__inverted"><div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"><nav class="content-tabs content-tabs--books"><ul><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">
Video + UX Training</button></a></li><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">Video only</button></a></li></ul></nav><div class="book-cta__col book-cta__hardcover content-tab--content"><h3 class="book-cta__title"><span>Video + UX Training</span></h3><span class="book-cta__price"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>495<span class="sup">.00</span></span></span> <span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>799<span class="sup">.00</span></span></span></span></span>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3951439" class="btn btn--full btn--medium btn--text-shadow">
Get Video + UX Training<div></div></a><p class="book-cta__desc">25 video lessons (8h) + <a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/">Live UX Training</a>.<br>100 days money-back-guarantee.</p></div><div class="book-cta__col book-cta__ebook content-tab--content"><h3 class="book-cta__title"><span>Video only</span></h3><div data-audience="anonymous free supporter" data-remove="true"><span class="book-cta__price" data-handler="PriceTag"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>250<span class="sup">.00</span></span></span><span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>395<span class="sup">.00</span></span></span></span></div>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3950630" class="btn btn--full btn--medium btn--text-shadow">
Get the video course<div></div></a><p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true">25 video lessons (8h). Updated yearly.<br>Also available as a <a href="https://smart-interface-design-patterns.thinkific.com/enroll/3570306?price_id=4503439">UX Bundle with 3 video courses.</a></p></div><span></span></div></div>

<h2 id="useful-resources">Useful Resources</h2>

<ul>
<li>“<a href="https://measure-ux.com">How To Measure UX and Design Impact</a>”, by yours truly</li>
<li>“<a href="https://thecdo.school/books">Business Thinking For Designers</a>”, by Ryan Rumsey</li>
<li>“<a href="https://www.linkedin.com/feed/update/urn:li:activity:7338462034763661312/">ROI of Design Project</a></li>
<li>“<a href="https://articles.centercentre.com/how-the-right-ux-metrics-show-game-changing-value/">How the Right UX Metrics Show Game-Changing Value</a>”, by Jared Spool</li>
<li>“<a href="https://www.linkedin.com/posts/vitalyfriedman_ux-design-research-activity-7164173642887606274-rEqq">Research Sample Size Calculators</a>”</li>
</ul>

<h3 id="further-reading">Further Reading</h3>

<ul>
<li>“<a href="https://www.smashingmagazine.com/2025/11/designing-for-stress-emergency/">Designing For Stress And Emergency</a>”, Vitaly Friedman</li>
<li>“<a href="https://www.smashingmagazine.com/2025/10/ai-ux-achieve-more-with-less/">AI In UX: Achieve More With Less</a>”, Paul Boag</li>
<li>“<a href="https://www.smashingmagazine.com/2025/11/accessibility-problem-authentication-methods-captcha/">The Accessibility Problem With Authentication Methods Like CAPTCHA</a>”, Eleanor Hecks</li>
<li>“<a href="https://www.smashingmagazine.com/2025/09/from-prompt-to-partner-designing-custom-ai-assistant/">From Prompt To Partner: Designing Your Custom AI Assistant</a>”, Lyndon Cerejo</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Andy Clarke</author><title>Smashing Animations Part 7: Recreating Toon Text With CSS And SVG</title><link>https://www.smashingmagazine.com/2025/12/smashing-animations-part-7-recreating-toon-text-css-svg/</link><pubDate>Wed, 17 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/smashing-animations-part-7-recreating-toon-text-css-svg/</guid><description>In this article, pioneering author and web designer &lt;a href="https://stuffandnonsense.co.uk">Andy Clarke&lt;/a> shows his techniques for creating &lt;a href="https://stuffandnonsense.co.uk/toon-text/index.html">Toon Text titles&lt;/a> using modern CSS and SVG.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/smashing-animations-part-7-recreating-toon-text-css-svg/" />
              <title>Smashing Animations Part 7: Recreating Toon Text With CSS And SVG</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Smashing Animations Part 7: Recreating Toon Text With CSS And SVG</h1>
                  
                    
                    <address>Andy Clarke</address>
                  
                  <time datetime="2025-12-17T10:00:00&#43;00:00" class="op-published">2025-12-17T10:00:00+00:00</time>
                  <time datetime="2025-12-17T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>After finishing a project that required me to learn everything I could about CSS and SVG animations, I started writing this series about Smashing Animations and “<a href="https://www.smashingmagazine.com/2025/05/smashing-animations-part-1-classic-cartoons-inspire-css/">How Classic Cartoons Inspire Modern CSS</a>.” To round off this year, I want to show you how to use modern CSS to create that element that makes Toon Titles so impactful: their typography.</p>

<h2 id="title-artwork-design">Title Artwork Design</h2>

<p>In the silent era of the 1920s and early ’30s, the typography of a film’s title card created a mood, set the scene, and reminded an audience of the type of film they’d paid to see.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="156"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png"
			
			sizes="100vw"
			alt="Typographic title cards from the early years of cinema"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Typographic title cards from the early years of cinema. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/1-typographic-title-cards.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Cartoon title cards were also branding, mood, and scene-setting, all rolled into one. In the early years, when major studio budgets were bigger, these title cards were often illustrative and painterly.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="300"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png"
			
			sizes="100vw"
			alt="Top: William Hanna and Joseph Barbera’s 1940s Tom &amp; Jerry title cards. Bottom: Colour versions released in 1957. © Warner Bros. Entertainment Inc."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Top: William Hanna and Joseph Barbera’s 1940s Tom & Jerry title cards. Bottom: Colour versions released in 1957. © Warner Bros. Entertainment Inc. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/2-tom-jerry-title-cards.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>But when television boomed during the 1950s, budgets dropped, and cards designed by artists like Lawrence “Art” Goble adopted a new visual language, becoming more graphic, stylised, and less intricate.</p>

<p><strong>Note:</strong> <em>Lawrence “Art” Goble is one of the often overlooked heroes of mid-century American animation. He primarily worked for Hanna-Barbera during its most influential years of the 1950s and 1960s.</em></p>

<p>Goble wasn’t a character animator. His role was to create atmosphere, so he designed environments for <em>The Flintstones</em>, <em>Huckleberry Hound</em>, <em>Quick Draw McGraw</em>, and <em>Yogi Bear</em>, as well as the opening title cards that set the tone. His title cards, featuring paintings with a logo overlaid, helped define the iconic look of Hanna-Barbera.</p>

<p>Goble’s artwork for characters such as Quick Draw McGraw and Yogi Bear was effective on smaller TV screens. Rather than reproducing a still from the cartoon, he focused on presenting a single, strong idea &mdash; often in silhouette &mdash; that captured its essence. In “The Buzzin’ Bear,” Yogi buzzes by in a helicopter. He bounces away, pic-a-nic basket in hand, in “Bear on a Picnic,” and for his “Prize Fight Fright,” Yogi boxes the title text.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="300"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png"
			
			sizes="100vw"
			alt="Title cards for Hanna-Barbera’s Yogi Bear."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Title cards for Hanna-Barbera’s Yogi Bear. © Warner Bros. Entertainment Inc. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/3-title-cards-yogi-bear.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>With little or no motion to rely on, Goble’s single frames had to create a mood, set the scene, and describe a story. They did this using flat colours, graphic shapes, and typography that was frequently integrated into the artwork.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="225"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png"
			
			sizes="100vw"
			alt="Title cards for Hanna-Barbera’s Quick Draw McGraw."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Title cards for Hanna-Barbera’s Quick Draw McGraw. © Warner Bros. Entertainment Inc. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/4-title-cards-quick-draw-mcgraw.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>As designers who work on the web, toon titles can teach us plenty about how to convey a brand’s personality, make a first impression, and set expectations for someone’s experience using a product or website. We can learn from the artists’ techniques to create effective banners, landing-page headers, and even good ol’ fashioned splash screens.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="toon-title-typography">Toon Title Typography</h2>

<p>Cartoon title cards show how merging type with imagery delivers the punch a header or hero needs. With a handful of <code>text-shadow</code>, <code>text-stroke</code>, and <code>transform</code> tricks, modern CSS lets you tap into that same energy.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="455"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png"
			
			sizes="100vw"
			alt="Title cards for Hanna-Barbera’s Augie Doggie."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Title cards for Hanna-Barbera’s Augie Doggie. © Warner Bros. Entertainment Inc. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/5-title-cards-augie-doggie.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="the-toon-text-title-generator">The Toon Text Title Generator</h2>

<p>Partway through writing this article, I realised it would be useful to have a tool for generating text styled like the cartoon titles I love so much. <a href="https://stuffandnonsense.co.uk/toon-text/tool.html">So I made one.</a></p>

<p>My Toon Text Title Generator lets you experiment with colours, strokes, and multiple text shadows. You can adjust paint order, apply letter spacing, preview your text in a selection of sample fonts, and then copy the generated CSS straight to your clipboard to use in a project.</p>

<h2 id="toon-title-css">Toon Title CSS</h2>

<p>You can simply copy-paste the CSS that the Toon Text Title Generator provides you. But let’s look closer at what it does.</p>

<h3 id="text-shadow">Text shadow</h3>

<p>Look at the type in this title from Augie Doggie’s episode “Yuk-Yuk Duck,” with its pale yellow letters and dark, hard, offset shadow that lifts it off the background and creates the illusion of depth.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/6-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>You probably already know that <code>text-shadow</code> accepts four values: (1) horizontal and (2) vertical offsets, (3) blur, and (4) a colour which can be solid or semi-transparent. Those offset values can be positive or negative, so I can replicate “Yuk-Yuk Duck” using a hard shadow pulled down and to the right:</p>

<pre><code class="language-css">color: &#35;f7f76d;
text-shadow: 5px 5px 0 &#35;1e1904;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/7-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>On the other hand, this “Pint Giant” title has a different feel with its negative semi-soft shadow:</p>

<pre><code class="language-css">color: &#35;c2a872;
text-shadow:
  -7px 5px 0 &#35;b100e,
  0 -5px 10px &#35;546c6f;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/8-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To add extra depth and create more interesting effects, I can layer multiple shadows. For “Let’s Duck Out,” I combine four shadows: the first a solid shadow with a negative horizontal offset to lift the text off the background, followed by progressively softer shadows to create a blur around it:</p>

<pre><code class="language-css">color: &#35;6F4D80;
text-shadow:
  -5px 5px 0 &#35;260e1e, /&#42; Shadow 1 &#42;/
  0 0 15px &#35;e9ce96,   /&#42; Shadow 2 &#42;/
  0 0 30px &#35;e9ce96,   /&#42; Shadow 3 &#42;/
  0 0 30px &#35;e9ce96;   /&#42; Shadow 4 &#42;/
</code></pre>

<p>These shadows show that using <code>text-shadow</code> isn’t just about creating lighting effects, as they can also be decorative and add personality.</p>

<h3 id="text-stroke">Text Stroke</h3>

<p>Many cartoon title cards feature letters with a bold outline that makes them stand out from the background. I can recreate this effect using <code>text-stroke</code>. For a long time, this property was only available via a <code>-webkit-</code> prefix, but that also means it’s now supported across modern browsers.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/9-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p><code>text-stroke</code> is a shorthand for two properties. The first, <code>text-stroke-width</code>, draws a contour around individual letters, while the second, <code>text-stroke-color</code>, controls its colour. For “Whatever Goes Pup,” I added a <code>4px</code> blue stroke to the yellow text:</p>

<pre><code class="language-css">color: &#35;eff0cd;
-webkit-text-stroke: 4px &#35;7890b5;
text-stroke: 4px &#35;7890b5;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/10-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Strokes can be especially useful when they’re combined with shadows, so for “Growing, Growing, Gone,” I added a thin <code>3px</code> stroke to a barely blurred <code>1px</code> shadow to create this three-dimensional text effect:</p>

<pre><code class="language-css">color: &#35;fbb999;
text-shadow: 3px 5px 1px &#35;5160b1;
-webkit-text-stroke: 3px &#35;984336;
text-stroke: 3px &#35;984336;
</code></pre>

<h3 id="paint-order">Paint Order</h3>

<p>Using <code>text-stroke</code> doesn’t always produce the expected result, especially with thinner letters and thicker strokes, because by default the browser draws a stroke over the fill. Sadly, CSS still does not permit me to adjust stroke placement as I often do in Sketch. However, the <code>paint-order</code> property has values that allow me to place the stroke behind, rather than in front of, the fill.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png"
			
			sizes="100vw"
			alt="Left: paint-order: stroke; Right: paint-order: fill."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Left: <code>paint-order: stroke</code>. Right: <code>paint-order: fill</code>. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/11-paint-order.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p><code>paint-order: stroke</code> paints the stroke first, then the fill, whereas <code>paint-order: fill</code> does the opposite:</p>

<pre><code class="language-css">color: &#35;fbb999;
paint-order: fill;
text-shadow: 3px 5px 1px &#35;5160b1;
text-stroke-color:&#35;984336;
text-stroke-width: 3px;
</code></pre>

<p>An effective stroke keeps letters readable, adds weight, and &mdash; when combined with shadows and paint order &mdash; gives flat text real presence.</p>

<div class="partners__lead-place"></div>

<h2 id="backgrounds-inside-text">Backgrounds Inside Text</h2>

<p>Many cartoon title cards go beyond flat colour by adding texture, gradients, or illustrated detail to the lettering. Sometimes that’s a texture, other times it might be a gradient with a subtle tonal shift. On the web, I can recreate this effect by using a background image or gradient behind the text, and then clipping it to the shape of the letters. This relies on two properties working together: <code>background-clip: text</code> and <code>text-fill-color: transparent</code>.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/12-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>First, I apply a background behind the text. This can be a bitmap or vector image or a CSS gradient. For this example from the Quick Draw McGraw episode “Baba Bait,” the title text includes a subtle top–bottom gradient from dark to light:</p>

<pre><code class="language-css">background: linear-gradient(0deg, &#35;667b6a, &#35;1d271a);
</code></pre>

<p>Next, I clip that background to the glyphs and make the text transparent so the background shows through:</p>

<pre><code class="language-css">-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
</code></pre>

<p>With just those two lines, the background is no longer painted behind the text; instead, it’s painted within it. This technique works especially well when combined with strokes and shadows. A clipped gradient provides the lettering with colour and texture, a stroke keeps its edges sharp, and a shadow elevates it from the background. Together, they recreate the layered look of hand-painted title cards using nothing more than a little CSS. As always, test clipped text carefully, as browser quirks can sometimes affect shadows and rendering.</p>

<h3 id="splitting-text-into-individual-characters">Splitting Text Into Individual Characters</h3>

<p>Sometimes I don’t want to style a whole word or heading. I want to style individual letters &mdash; to nudge a character into place, give one glyph extra weight, or animate a few letters independently.</p>

<p>In plain HTML and CSS, there’s only one reliable way to do that: wrap each character in its own <code>span</code> element. I could do that manually, but that would be fragile, hard to maintain, and would quickly fall apart when copy changes. Instead, when I need per-letter control, I use a text-splitting library like <a href="https://www.spltjs.com">splt.js</a> (although other solutions are available). This takes a text node and automatically wraps words or characters, giving me extra hooks to animate and style without messing up my markup.</p>

<p>It’s an approach that keeps my HTML readable and semantic, while giving me the fine-grained control I need to recreate the uneven, characterful typography you see in classic cartoon title cards. However, this approach comes with accessibility caveats, as most screen readers read text nodes in order. So this:</p>

<pre><code class="language-html">&lt;h2&gt;Hum Sweet Hum&lt;/h2&gt;
</code></pre>

<p>…reads as you’d expect:</p>

<blockquote>Hum Sweet Hum</blockquote>

<p>But this:</p>

<pre><code class="language-html">&lt;h2&gt;
&lt;span&gt;H&lt;/span&gt;
&lt;span&gt;u&lt;/span&gt;
&lt;span&gt;m&lt;/span&gt;
&lt;!-- etc. --&gt;
&lt;/h2&gt;
</code></pre>

<p>…can be interpreted differently depending on the browser and screen reader. Some will concatenate the letters and read the words correctly. Others may pause between letters, which in a worst-case scenario might sound like:</p>

<blockquote>“H…” “U…” “M…”</blockquote>

<p>Sadly, some splitting solutions don’t deliver an always accessible result, so I’ve written my own text splitter, <a href="https://stuffandnonsense.co.uk/toon-text/splinter.html#section-install">splinter.js</a>, which is currently in beta.</p>

<h3 id="transforming-individual-letters">Transforming Individual Letters</h3>

<p>To activate my Toon Text Splitter, I add a <code>data-</code> attribute to the element I want to split:</p>

<pre><code class="language-html">&lt;h2 data-split="toon"&gt;Hum Sweet Hum&lt;/h2&gt;
</code></pre>

<p>First, my script separates each word into individual letters and wraps them in a <code>span</code> element with class and ARIA attributes applied:</p>

<pre><code class="language-html">&lt;span class="toon-char" aria-hidden="true"&gt;H&lt;/span&gt;
&lt;span class="toon-char" aria-hidden="true"&gt;u&lt;/span&gt;
&lt;span class="toon-char" aria-hidden="true"&gt;m&lt;/span&gt;
</code></pre>

<p>The script then takes the initial content of the split element and adds it as an aria attribute to help maintain accessibility:</p>

<div class="break-out">
<pre><code class="language-html">&lt;h2 data-split="toon" aria-label="Hum Sweet Hum"&gt;
  &lt;span class="toon-char" aria-hidden="true"&gt;H&lt;/span&gt;
  &lt;span class="toon-char" aria-hidden="true"&gt;u&lt;/span&gt;
  &lt;span class="toon-char" aria-hidden="true"&gt;m&lt;/span&gt;
&lt;/h2&gt;
</code></pre>
</div>

<p>With those class attributes applied, I can then style individual characters as I choose.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/13-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>For example, for “Hum Sweet Hum,” I want to replicate how its letters shift away from the baseline. After using my Toon Text Splitter, I applied four different <code>translate</code> values using several <code>:nth-child</code> selectors to create a semi-random look:</p>

<pre><code class="language-css">/&#42; 4th, 8th, 12th... &#42;/
.toon-char:nth-child(4n) { translate: 0 -8px; }
/&#42; 1st, 5th, 9th... &#42;/
.toon-char:nth-child(4n+1) { translate: 0 -4px; }
/&#42; 2nd, 6th, 10th... &#42;/
.toon-char:nth-child(4n+2) { translate: 0 4px; }
/&#42; 3rd, 7th, 11th... &#42;/
.toon-char:nth-child(4n+3) { translate: 0 8px; }
</code></pre>

<p>But <code>translate</code> is only one property I can use to <code>transform</code> my toon text.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/14-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I could also rotate those individual characters for an even more chaotic look:</p>

<pre><code class="language-css">/&#42; 4th, 8th, 12th... &#42;/
.toon-line .toon-char:nth-child(4n) { rotate: -4deg; }
/&#42; 1st, 5th, 9th... &#42;/
.toon-char:nth-child(4n+1) { rotate: -8deg; }
/&#42; 2nd, 6th, 10th... &#42;/
.toon-char:nth-child(4n+2) { rotate: 4deg; }
/&#42; 3rd, 7th, 11th... &#42;/
.toon-char:nth-child(4n+3) { rotate: 8deg; }
</code></pre>

<p>But <code>translate</code> is only one property I can use to <code>transform</code> my toon text. I could also <code>rotate</code> those individual characters for an even more chaotic look:</p>

<pre><code class="language-css">/&#42; 4th, 8th, 12th... &#42;/
.toon-line .toon-char:nth-child(4n) {
rotate: -4deg; }

/&#42; 1st, 5th, 9th... &#42;/
.toon-char:nth-child(4n+1) {
rotate: -8deg; }

/&#42; 2nd, 6th, 10th... &#42;/
.toon-char:nth-child(4n+2) {
rotate: 4deg; }

/&#42; 3rd, 7th, 11th... &#42;/
.toon-char:nth-child(4n+3) {
rotate: 8deg; }
</code></pre>

<p>And, of course, I could add animations to jiggle those characters and bring my toon text style titles to life. First, I created a keyframe animation that rotates the characters:</p>

<div class="break-out">
<pre><code class="language-css">@keyframes jiggle {
0%, 100% { transform: rotate(var(--base-rotate, 0deg)); }
25% { transform: rotate(calc(var(--base-rotate, 0deg) + 3deg)); }
50% { transform: rotate(calc(var(--base-rotate, 0deg) - 2deg)); }
75% { transform: rotate(calc(var(--base-rotate, 0deg) + 1deg)); }
}
</code></pre>
</div>

<p>Before applying it to the <code>span</code> elements created by my Toon Text Splitter:</p>

<pre><code class="language-css">.toon-char {
animation: jiggle 3s infinite ease-in-out;
transform-origin: center bottom; }
</code></pre> 

<p>And finally, setting the rotation amount and a delay before each character begins to jiggle:</p>

<pre><code class="language-css">.toon-char:nth-child(4n) { --base-rotate: -2deg; }
.toon-char:nth-child(4n+1) { --base-rotate: -4deg; }
.toon-char:nth-child(4n+2) { --base-rotate: 2deg; }
.toon-char:nth-child(4n+3) { --base-rotate: 4deg; }

.toon-char:nth-child(4n) { animation-delay: 0.1s; }
.toon-char:nth-child(4n+1) { animation-delay: 0.3s; }
.toon-char:nth-child(4n+2) { animation-delay: 0.5s; }
.toon-char:nth-child(4n+3) { animation-delay: 0.7s; }
</code></pre> 














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="317"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png"
			
			sizes="100vw"
			alt="Example from Andy&#39;s Toon Text collection."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      See this example in my Toon Text collection. (<a href='https://files.smashing.media/articles/smashing-animations-part-7-recreating-toon-text-css-svg/15-toon-text-collection.png'>Large preview</a>)
    </figcaption>
  
</figure>

<div class="partners__lead-place"></div>

<h2 id="one-frame-to-make-an-impression">One Frame To Make An Impression</h2>

<p>Cartoon title artists had one frame to make an impression, and their typography was as important as the artwork they painted. The same is true on the web.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aA%20well-designed%20header%20or%20hero%20area%20needs%20clarity,%20character,%20and%20confidence%20%e2%80%94%20not%20simply%20a%20faded%20full-width%20background%20image.%0a&url=https://smashingmagazine.com%2f2025%2f12%2fsmashing-animations-part-7-recreating-toon-text-css-svg%2f">
      
A well-designed header or hero area needs clarity, character, and confidence — not simply a faded full-width background image.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>With a few carefully chosen CSS properties &mdash; shadows, strokes, clipped backgrounds, and some restrained animation &mdash; we can recreate that same impact. I love toon text not because I’m nostalgic, but because its design is intentional. Make deliberate choices, and let a little toon text typography add punch to your designs.</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Brecht De Ruyte</author><title>State, Logic, And Native Power: CSS Wrapped 2025</title><link>https://www.smashingmagazine.com/2025/12/state-logic-native-power-css-wrapped-2025/</link><pubDate>Tue, 09 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/state-logic-native-power-css-wrapped-2025/</guid><description>CSS Wrapped 2025 is out! We’re entering a world where CSS can increasingly handle logic, state, and complex interactions once reserved for JavaScript. It’s no longer just about styling documents, but about crafting dynamic, ergonomic, and robust applications with a native toolkit more powerful than ever. Here’s an unpacking of the highlights and how they connect to the broader evolution of modern CSS.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/state-logic-native-power-css-wrapped-2025/" />
              <title>State, Logic, And Native Power: CSS Wrapped 2025</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>State, Logic, And Native Power: CSS Wrapped 2025</h1>
                  
                    
                    <address>Brecht De Ruyte</address>
                  
                  <time datetime="2025-12-09T10:00:00&#43;00:00" class="op-published">2025-12-09T10:00:00+00:00</time>
                  <time datetime="2025-12-09T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>If I were to divide CSS evolutions into categories, we have moved far beyond the days when we simply asked for <code>border-radius</code> to feel like we were living in the future. We are currently living in a moment where the platform is handing us tools that don’t just tweak the visual layer, but fundamentally redefine how we architect interfaces. I thought the number of features announced in 2024 couldn’t be topped. I’ve never been so happily wrong.</p>

<p>The Chrome team’s “<a href="https://chrome.dev/css-wrapped-2025/"><strong>CSS Wrapped 2025</strong></a>” is not just a list of features; it is a manifesto for a dynamic, native web. As someone who has spent a couple of years documenting these evolutions &mdash; from <a href="https://www.smashingmagazine.com/2024/08/css5-era-evolution/">defining “CSS5” eras</a> to the intricacies of <a href="https://www.smashingmagazine.com/2024/05/modern-css-layouts-no-framework/">modern layout utilities</a> &mdash; I find myself looking at this year’s wrap-up with a huge sense of excitement. We are seeing a shift towards “Optimized Ergonomics” and “Next-gen interactions” that allow us to stop fighting the code and start sculpting interfaces in their natural state.</p>

<p>In this article, you can find <strong>a comprehensive look at the standout features from Chrome’s report</strong>, viewed through the lens of my recent experiments and hopes for the future of the platform.</p>

<h2 id="the-component-revolution-finally-a-native-customizable-select">The Component Revolution: Finally, A Native Customizable Select</h2>

<p>For years, we have relied on heavy JavaScript libraries to style dropdowns, a “decades-old problem” that the platform has finally solved. As I detailed in <a href="https://utilitybend.com/blog/the-customizable-select-part-one-history-trickery-and-styling-the-select-with-css">my deep dive into the history of the customizable select</a> (and related articles), this has been a long road involving <a href="https://open-ui.org/">Open UI</a>, bikeshedding names like <code>&lt;selectmenu&gt;</code> and <code>&lt;selectlist&gt;</code>, and finally landing on a solution that re-uses the existing <code>&lt;select&gt;</code> element.</p>

<p>The introduction of <code>appearance: base-select</code> is a strong foundation. It allows us to fully customize the <code>&lt;select&gt;</code> element &mdash; including the button and the dropdown list (via <code>::picker(select)</code>) &mdash; using standard CSS. Crucially, this is built with progressive enhancement in mind. By wrapping our styles in a feature query, we ensure a seamless experience across all browsers.</p>

<p>We can opt in to this new behavior without breaking older browsers:</p>

<pre><code class="language-css">select {
  /&#42; Opt-in for the new customizable select &#42;/
  @supports (appearance: base-select) {
    &, &::picker(select) {
      appearance: base-select;
    }
  }
}
</code></pre>

<p>The fantastic addition to allow rich content inside options, such as images or flags, is a lot of fun. We can create all sorts of selects nowadays:</p>

<ul>
<li><strong>Demo:</strong> I created a <a href="https://codepen.io/utilitybend/pen/ByawgNN">Poké-adventure demo</a> showing how the new <code>&lt;selectedcontent&gt;</code> element can clone rich content (like a Pokéball icon) from an option directly into the button.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="JoXwwoZ"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [A customizable select with images inside of the options and the selectedcontent [forked]](https://codepen.io/smashingmag/pen/JoXwwoZ) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/JoXwwoZ">A customizable select with images inside of the options and the selectedcontent [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<ul>
<li><strong>Demo:</strong> A comprehensive look at <a href="https://codepen.io/utilitybend/pen/GgRrLWb">styling the select with only pseudo-elements</a>.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="pvyqqJR"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [A customizable select with only pseudo-elements [forked]](https://codepen.io/smashingmag/pen/pvyqqJR) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/pvyqqJR">A customizable select with only pseudo-elements [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<ul>
<li><strong>Demo:</strong> Or you can kick it up a notch with this <a href="https://codepen.io/utilitybend/pen/ByoBMBm">Menu selection demo using optgroups</a>.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="myPaaJZ"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [An actual Select Menu with optgroups [forked]](https://codepen.io/smashingmag/pen/myPaaJZ) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/myPaaJZ">An actual Select Menu with optgroups [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<p>This feature alone signals a massive shift in how we will build forms, reducing dependencies and technical debt.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="scroll-markers-and-the-death-of-the-javascript-carousel">Scroll Markers And The Death Of The JavaScript Carousel</h2>

<p>Creating carousels has historically been a friction point between developers and clients. Clients love them, developers dread the JavaScript required to make them accessible and performant. The arrival of <code>::scroll-marker</code> and <code>::scroll-button()</code> pseudo-elements changes this dynamic entirely.</p>

<p>These features allow us to create navigation dots and scroll buttons purely with CSS, linked natively to the scroll container. As I wrote on my blog, this was <a href="https://utilitybend.com/blog/love-at-first-slide-creating-a-carousel-purely-out-of-css">Love at first slide</a>. The ability to create a fully functional, accessible slider without a single line of JavaScript is not just convenient; it is a triumph for performance. There are some accessibility concerns around this feature, and even though these are valid, there might be a way for us developers to make it work. The good thing is, all these UI changes are making it a lot easier than custom DOM manipulation and dragging around aria tags, but I digress…</p>

<p>We can now group markers automatically using <code>scroll-marker-group</code> and style the buttons using anchor positioning to place them exactly where we want.</p>

<div class="break-out">
<pre><code class="language-css">.carousel {
  overflow-x: auto;
  scroll-marker-group: after; /&#42; Creates the container for dots &#42;/

  /&#42; Create the buttons &#42;/
  &::scroll-button(inline-end),
  &::scroll-button(inline-start) {
    content: " ";
    position: absolute;
    /&#42; Use anchor positioning to center them &#42;/
    position-anchor: --carousel;
    top: anchor(center);
  }

  /&#42; Create the markers on the children &#42;/
  div {
    &::scroll-marker {
      content: " ";
      width: 24px;
      border-radius: 50%;
      cursor: pointer;
    }
    /&#42; Highlight the active marker &#42;/
    &::scroll-marker:target-current {
      background: white;
    }
  }
}
</code></pre>
</div>

<ul>
<li><strong>Demo:</strong> My experiment creating a <a href="https://codepen.io/utilitybend/pen/vEBQxNb">carousel purely out of HTML and CSS</a>, using anchor positioning to place the buttons.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="ogxJJjQ"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [Carousel Pure HTML and CSS [forked]](https://codepen.io/smashingmag/pen/ogxJJjQ) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/ogxJJjQ">Carousel Pure HTML and CSS [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<ul>
<li><strong>Demo:</strong> A <a href="https://codepen.io/utilitybend/pen/bNbXZWb">Webshop slick slider remake</a> using <code>attr()</code> to pull background images dynamically into the markers.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="gbrZZPY"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [Webshop slick slider remake in CSS [forked]](https://codepen.io/smashingmag/pen/gbrZZPY) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/gbrZZPY">Webshop slick slider remake in CSS [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<h2 id="state-queries-sticky-thing-stuck-snappy-thing-snapped">State Queries: Sticky Thing Stuck? Snappy Thing Snapped?</h2>

<p>For a long time, we have lacked the ability to know if a <a href="https://utilitybend.com/blog/is-the-sticky-thing-stuck-is-the-snappy-item-snapped-a-look-at-state-queries-in-css">“sticky thing is stuck” or if a “snappy item is snapped”</a> without relying on IntersectionObserver hacks. Chrome 133 introduced scroll-state queries, allowing us to query these states declaratively.</p>

<p>By setting <code>container-type: scroll-state</code>, we can now style children based on whether they are stuck, snapped, or overflowing. This is a massive “quality of life” improvement that I have been eagerly waiting for since CSS Day 2023. It has even evolved a lot since we can also see the direction of the scroll, lovely!</p>

<p>For a simple example: we can finally apply a shadow to a header <em>only</em> when it is actually sticking to the top of the viewport:</p>

<pre><code class="language-css">.header-container {
  container-type: scroll-state;
  position: sticky;
  top: 0;

  header {
    transition: box-shadow 0.5s ease-out;
    /&#42; The query checks the state of the container &#42;/
    @container scroll-state(stuck: top) {
      box-shadow: rgba(0, 0, 0, 0.6) 0px 12px 28px 0px;
    }
  }
}
</code></pre>

<ul>
<li><strong>Demo:</strong> A <a href="https://codepen.io/utilitybend/pen/XWLQPOe">sticky header</a> that only applies a shadow when it is actually stuck.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="raeooxY"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [Sticky headers with scroll-state query, checking if the sticky element is stuck [forked]](https://codepen.io/smashingmag/pen/raeooxY) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/raeooxY">Sticky headers with scroll-state query, checking if the sticky element is stuck [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<ul>
<li><strong>Demo:</strong> A <a href="https://codepen.io/utilitybend/pen/MWMZoqp">Pokémon-themed list</a> that uses scroll-state queries combined with anchor positioning to move a frame over the currently snapped character.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="vEGvvLM"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [Scroll-state query to check which item is snapped with CSS, Pokemon version [forked]](https://codepen.io/smashingmag/pen/vEGvvLM) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/vEGvvLM">Scroll-state query to check which item is snapped with CSS, Pokemon version [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<div class="partners__lead-place"></div>

<h2 id="optimized-ergonomics-logic-in-css">Optimized Ergonomics: Logic In CSS</h2>

<p>The “Optimized Ergonomics” section of CSS Wrapped highlights features that make our workflows more intuitive. Three features stand out as transformative for how we write logic:</p>

<ol>
<li><strong><code>if()</code> Statements</strong><br />
We are finally getting conditionals in CSS. The <code>if()</code> function acts like a ternary operator for stylesheets, allowing us to apply values based on media, support, or style queries inline. This reduces the need for verbose <code>@media</code> blocks for single property changes.</li>
<li><strong><code>@function</code> functions</strong><br />
We can finally move some logic to a different place, resulting in some cleaner files, a real quality of life feature.</li>
<li><strong><code>sibling-index()</code> and <code>sibling-count()</code></strong><br />
These tree-counting functions solve the issue of staggering animations or styling items based on list size. As I explored in <a href="https://utilitybend.com/blog/styling-siblings-with-css-has-never-been-easier-experimenting-with-sibling-count-and-sibling-index">Styling siblings with CSS has never been easier</a>, this eliminates the need to hard-code custom properties (like <code>--index: 1</code>) in our HTML.</li>
</ol>

<h3 id="example-calculating-layouts">Example: Calculating Layouts</h3>

<p>We can now write concise mathematical formulas. For example, staggering an animation for cards entering the screen becomes trivial:</p>

<pre><code class="language-css">.card-container &gt; &#42; {
  animation: reveal 0.6s ease-out forwards;
  /&#42; No more manual --index variables! &#42;/
  animation-delay: calc(sibling-index() &#42; 0.1s);
}
</code></pre>

<p>I even experimented with using these functions along with trigonometry to place items in a perfect circle without any JavaScript.</p>

<ul>
<li><strong>Demo:</strong> <a href="https://codepen.io/utilitybend/pen/wBKQPLr">Staggering card animations dynamically</a>.</li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="RNaEERz"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [Stagger cards using sibling-index() [forked]](https://codepen.io/smashingmag/pen/RNaEERz) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/RNaEERz">Stagger cards using sibling-index() [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<ul>
<li><strong>Demo:</strong> Placing items in a <a href="https://codepen.io/utilitybend/pen/VYvVXLN">perfect circle</a> using <code>sibling-index</code>, <code>sibling-count</code>, and the new CSS <code>@function</code> feature.
<br /></li>
</ul>

<figure class="break-out">
	<p data-height="480"
	data-theme-id="light"
	data-slug-hash="XJdoojZ"
	data-user="smashingmag"
	data-default-tab="result"
	class="codepen">See the Pen [The circle using sibling-index, sibling-count and functions [forked]](https://codepen.io/smashingmag/pen/XJdoojZ) by <a href="https://codepen.io/utilitybend">utilitybend</a>.</p>
	<figcaption>See the Pen <a href="https://codepen.io/smashingmag/pen/XJdoojZ">The circle using sibling-index, sibling-count and functions [forked]</a> by <a href="https://codepen.io/utilitybend">utilitybend</a>.</figcaption>
</figure>

<h2 id="my-css-to-do-list-features-i-can-t-wait-to-try">My CSS To-Do List: Features I Can’t Wait To Try</h2>

<p>While I have been busy sculpting selects and transitions, the “CSS Wrapped 2025” report is packed with other goodies that I haven’t had the chance to fire up in CodePen yet. These are high on my list for my next experiments:</p>

<h3 id="anchored-container-queries">Anchored Container Queries</h3>

<p>I used CSS Anchor Positioning for the buttons in my carousel demo, but “CSS Wrapped” highlights an evolution of this: <strong>Anchored Container Queries</strong>. This solves a problem we’ve all had with tooltips: if the browser flips the tooltip from top to bottom because of space constraints, the “arrow” often stays pointing the wrong way. With anchored container queries (<code>@container anchored(fallback: flip-block)</code>), we can style the element based on which fallback position the browser actually chose.</p>

<h3 id="nested-view-transition-groups">Nested View Transition Groups</h3>

<p>View Transitions have been a revolution, but they came with a specific trade-off: they flattened the element tree, which often broke 3D transforms or overflow: clip. I always had a feeling that it was missing something, and this might just be the answer. By using <code>view-transition-group: nearest</code>, we can finally nest transition groups within each other.</p>

<p>This allows us to maintain clipping effects or 3D rotations during a transition &mdash; something that was previously impossible because the elements were hoisted up to the top level.</p>

<pre><code class="language-css">.card img {
  view-transition-name: photo;
  view-transition-group: nearest; /&#42; Keep it nested! &#42;/
}
</code></pre>

<h3 id="typography-and-shapes">Typography and Shapes</h3>

<p>Finally, the ergonomist in me is itching to try <strong>Text Box Trim</strong>, which promises to remove that annoying extra whitespace above and below text content (the leading) to finally achieve perfect vertical alignment. And for the creative side, <code>corner-shape</code> and the <code>shape()</code> function are opening up non-rectangular layouts, allowing for “squaricles” and complex paths that respond to CSS variables. That being said, I can’t wait to have a design full of squircles!</p>

<div class="partners__lead-place"></div>

<h2 id="a-hopeful-future">A Hopeful Future</h2>

<p>We are witnessing a world where <strong>CSS is becoming capable of handling logic, state, and complex interactions that previously belonged to JavaScript</strong>. Features like <code>moveBefore</code> (preserving DOM state for iframes/videos) and <code>attr()</code> (using types beyond strings for colors and grids) further cement this reality.</p>

<p>While some of these features are currently experimental or specific to Chrome, the momentum is undeniable. We must hope for continued support across all browsers through initiatives like Interop to ensure these capabilities become the baseline. That being said, having browser engines is just as important as having all these awesome features in “Chrome first”. These new features need to be discussed, tinkered with, and tested before ever landing in browsers.</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aIt%20is%20a%20fantastic%20moment%20to%20get%20into%20CSS.%20We%20are%20no%20longer%20just%20styling%20documents;%20we%20are%20crafting%20dynamic,%20ergonomic,%20and%20robust%20applications%20with%20a%20native%20toolkit%20that%20is%20more%20powerful%20than%20ever.%0a&url=https://smashingmagazine.com%2f2025%2f12%2fstate-logic-native-power-css-wrapped-2025%2f">
      
It is a fantastic moment to get into CSS. We are no longer just styling documents; we are crafting dynamic, ergonomic, and robust applications with a native toolkit that is more powerful than ever.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<p>Let’s get going with this new era and spread the word.</p>

<p>This is <a href="https://chrome.dev/css-wrapped-2025/">CSS Wrapped</a>!</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Victor Yocco</author><title>Beyond The Black Box: Practical XAI For UX Practitioners</title><link>https://www.smashingmagazine.com/2025/12/beyond-black-box-practical-xai-ux-practitioners/</link><pubDate>Fri, 05 Dec 2025 15:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/beyond-black-box-practical-xai-ux-practitioners/</guid><description>Explainable AI isn’t just a challenge for data scientists. It’s also a design challenge and a core pillar of trustworthy, effective AI products. Victor Yocco offers practical guidance and design patterns for building explainability into real products.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/beyond-black-box-practical-xai-ux-practitioners/" />
              <title>Beyond The Black Box: Practical XAI For UX Practitioners</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Beyond The Black Box: Practical XAI For UX Practitioners</h1>
                  
                    
                    <address>Victor Yocco</address>
                  
                  <time datetime="2025-12-05T15:00:00&#43;00:00" class="op-published">2025-12-05T15:00:00+00:00</time>
                  <time datetime="2025-12-05T15:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>In my <a href="https://www.smashingmagazine.com/2025/09/psychology-trust-ai-guide-measuring-designing-user-confidence/">last piece</a>, we established a foundational truth: for users to adopt and rely on AI, they must <strong>trust</strong> it. We talked about trust being a multifaceted construct, built on perceptions of an AI’s <strong>Ability</strong>, <strong>Benevolence</strong>, <strong>Integrity</strong>, and <strong>Predictability</strong>. But what happens when an AI, in its silent, algorithmic wisdom, makes a decision that leaves a user confused, frustrated, or even hurt? A mortgage application is denied, a favorite song is suddenly absent from a playlist, and a qualified resume is rejected before a human ever sees it. In these moments, ability and predictability are shattered, and benevolence feels a world away.</p>

<p>Our conversation now  must evolve from the <em>why</em> of trust to the <em>how</em> of transparency. The field of <strong>Explainable AI (XAI)</strong>, which focuses on developing methods to make AI outputs understandable to humans, has emerged to address this, but it’s often framed as a purely technical challenge for data scientists. I argue it’s a critical design challenge for products relying on AI. It’s our job as UX professionals to bridge the gap between algorithmic decision-making and human understanding.</p>

<p>This article provides practical, actionable guidance on how to research and design for explainability. We’ll move beyond the buzzwords and into the mockups, translating complex XAI concepts into concrete design patterns you can start using today.</p>

<h2 id="de-mystifying-xai-core-concepts-for-ux-practitioners">De-mystifying XAI: Core Concepts For UX Practitioners</h2>

<p>XAI is about answering the user’s question: “<strong>Why?</strong>” Why was I shown this ad? Why is this movie recommended to me? Why was my request denied? Think of it as the AI showing its work on a math problem. Without it, you just have an answer, and you’re forced to take it on faith. In showing the steps, you build comprehension and trust. You also allow for your work to be double-checked and verified by the very humans it impacts.</p>

<h3 id="feature-importance-and-counterfactuals">Feature Importance And Counterfactuals</h3>

<p>There are a number of techniques we can use to clarify or explain what is happening with AI. While methods range from providing the entire logic of a decision tree to generating natural language summaries of an output, two of the most practical and impactful types of information UX practitioners can introduce into an experience are <strong>feature importance</strong> (Figure 1) and <strong>counterfactuals</strong>. These are often the most straightforward for users to understand and the most actionable for designers to implement.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="478"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png"
			
			sizes="100vw"
			alt="A fictional example of feature importance"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Figure 1: A fictional example of feature importance where a bank system shows the importance of various features that lead to a model’s decision. Image generated using Google Gemini. (<a href='https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/1-example-feature-importance.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h4 id="feature-importance">Feature Importance</h4>

<p>This explainability method answers, “<strong>What were the most important factors the AI considered?</strong>” It’s about identifying the top 2-3 variables that had the biggest impact on the outcome. It’s the headline, not the whole story.</p>

<blockquote><strong>Example</strong>: Imagine an AI that predicts whether a customer will churn (cancel their service). Feature importance might reveal that “number of support calls in the last month” and “recent price increases” were the two most important factors in determining if a customer was likely to churn.</blockquote>

<h4 id="counterfactuals">Counterfactuals</h4>

<p>This powerful method answers, “<strong>What would I need to change to get a different outcome?</strong>” This is crucial because it gives users a sense of agency. It transforms a frustrating “no” into an actionable “not yet.”</p>

<blockquote><strong>Example</strong>: Imagine a loan application system that uses AI. A user is denied a loan. Instead of just seeing “Application Denied,” a counterfactual explanation would also share, “If your credit score were 50 points higher, or if your debt-to-income ratio were 10% lower, your loan would have been approved.” This gives Sarah clear, actionable steps she can take to potentially get a loan in the future.</blockquote>

<h3 id="using-model-data-to-enhance-the-explanation">Using Model Data To Enhance The Explanation</h3>

<p>Although technical specifics are often handled by data scientists, it&rsquo;s helpful for UX practitioners to know that tools like <a href="https://www.geeksforgeeks.org/artificial-intelligence/introduction-to-explainable-aixai-using-lime/">LIME</a> (Local Interpretable Model-agnostic Explanations) which explains individual predictions by approximating the model locally, and <a href="https://shap.readthedocs.io/en/latest/example_notebooks/overviews/An%20introduction%20to%20explainable%20AI%20with%20Shapley%20values.html">SHAP</a> (SHapley Additive exPlanations) which uses a game theory approach to explain the output of any machine learning model are commonly used to extract these “why” insights from complex models. These libraries essentially help break down an AI’s decision to show which inputs were most influential for a given outcome.</p>

<p>When done properly, the data underlying an AI tool’s decision can be used to tell a powerful story. Let’s walk through feature importance and counterfactuals and show how the data science behind the decision can be utilized to enhance the user’s experience.</p>

<p>Now let’s cover feature importance with the assistance of <strong>Local Explanations (e.g., LIME)</strong> data: This approach answers, “<strong>Why did the AI make <em>this specific</em> recommendation for me, right now?</strong>” Instead of a general explanation of how the model works, it provides a focused reason for a single, specific instance. It’s personal and contextual.</p>

<blockquote><strong>Example</strong>: Imagine an AI-powered music recommendation system like Spotify. A local explanation would answer, “Why did the system recommend <strong>this specific</strong> song by Adele to <strong>you</strong> right now?” The explanation might be: “Because you recently listened to several other emotional ballads and songs by female vocalists.”</blockquote>

<p>Finally, let’s cover the inclusion of <strong>Value-based Explanations (e.g. Shapley Additive Explanations (SHAP)</strong> data to an explanation of a decision: This is a more nuanced version of feature importance that answers, “<strong>How did each factor push the decision one way or the other?</strong>” It helps visualize <em>what</em> mattered, and whether its influence was positive or negative.</p>

<blockquote><strong>Example</strong>: Imagine a bank uses an AI model to decide whether to approve a loan application.</blockquote>

<p><strong>Feature Importance</strong>: The model output might show that the applicant’s credit score, income, and debt-to-income ratio were the most important factors in its decision. This answers <em>what</em> mattered.</p>

<p><strong>Feature Importance with Value-Based Explanations (SHAP)</strong>: SHAP values would take feature importance further based on elements of the model.</p>

<ul>
<li>For an approved loan, SHAP might show that a high credit score significantly <em>pushed</em> the decision towards approval (positive influence), while a slightly higher-than-average debt-to-income ratio <em>pulled</em> it slightly away (negative influence), but not enough to deny the loan.</li>
<li>For a denied loan, SHAP could reveal that a low income and a high number of recent credit inquiries <em>strongly pushed</em> the decision towards denial, even if the credit score was decent.</li>
</ul>

<p>This helps the loan officer explain to the applicant beyond <em>what</em> was considered, to <em>how each factor contributed</em> to the final “yes” or “no” decision.</p>

<p>It’s crucial to recognize that the ability to provide good explanations often starts much earlier in the development cycle. Data scientists and engineers play a pivotal role by intentionally structuring models and data pipelines in ways that inherently support explainability, rather than trying to bolt it on as an afterthought.</p>

<p>Research and design teams can foster this by initiating early conversations with data scientists and engineers about user needs for understanding, contributing to the development of explainability metrics, and collaboratively prototyping explanations to ensure they are both accurate and user-friendly.</p>

<h2 id="xai-and-ethical-ai-unpacking-bias-and-responsibility">XAI And Ethical AI: Unpacking Bias And Responsibility</h2>

<p>Beyond building trust, XAI plays a critical role in addressing the profound <strong>ethical implications of AI</strong>*, particularly concerning algorithmic bias. Explainability techniques, such as analyzing SHAP values, can reveal if a model’s decisions are disproportionately influenced by sensitive attributes like race, gender, or socioeconomic status, even if these factors were not explicitly used as direct inputs.</p>

<p>For instance, if a loan approval model consistently assigns negative SHAP values to applicants from a certain demographic, it signals a potential bias that needs investigation, empowering teams to surface and mitigate such unfair outcomes.</p>

<p>The power of XAI also comes with the potential for “<strong>explainability washing</strong>.” Just as “greenwashing” misleads consumers about environmental practices, explainability washing can occur when explanations are designed to obscure, rather than illuminate, problematic algorithmic behavior or inherent biases. This could manifest as overly simplistic explanations that omit critical influencing factors, or explanations that strategically frame results to appear more neutral or fair than they truly are. It underscores the ethical responsibility of UX practitioners to design explanations that are genuinely transparent and verifiable.</p>

<p>UX professionals, in collaboration with data scientists and ethicists, hold a crucial responsibility in communicating the <em>why</em> of a decision, and also the limitations and potential biases of the underlying AI model. This involves setting realistic user expectations about AI accuracy, identifying where the model might be less reliable, and providing clear channels for recourse or feedback when users perceive unfair or incorrect outcomes. Proactively addressing these ethical dimensions will allow us to build AI systems that are truly just and trustworthy.</p>

<h2 id="from-methods-to-mockups-practical-xai-design-patterns">From Methods To Mockups: Practical XAI Design Patterns</h2>

<p>Knowing the concepts is one thing; designing them is another. Here’s how we can translate these XAI methods into intuitive design patterns.</p>

<h3 id="pattern-1-the-because-statement-for-feature-importance">Pattern 1: The &ldquo;Because&rdquo; Statement (for Feature Importance)</h3>

<p>This is the simplest and often most effective pattern. It’s a direct, plain-language statement that surfaces the primary reason for an AI’s action.</p>

<ul>
<li><strong>Heuristic</strong>: Be direct and concise. Lead with the single most impactful reason. Avoid jargon at all costs.</li>
</ul>

<blockquote><strong>Example</strong>: Imagine a music streaming service. Instead of just presenting a “Discover Weekly” playlist, you add a small line of microcopy.<br /><br /><strong>Song Recommendation</strong>: “Velvet Morning”<br />Because you listen to “The Fuzz” and other psychedelic rock.</blockquote>

<h3 id="pattern-2-the-what-if-interactive-for-counterfactuals">Pattern 2: The &ldquo;What-If&rdquo; Interactive (for Counterfactuals)</h3>

<p>Counterfactuals are inherently about empowerment. The best way to represent them is by giving users interactive tools to explore possibilities themselves. This is perfect for financial, health, or other goal-oriented applications.</p>

<ul>
<li><strong>Heuristic</strong>: Make explanations interactive and empowering. Let users see the cause and effect of their choices.</li>
</ul>

<blockquote><strong>Example</strong>: A loan application interface. After a denial, instead of a dead end, the user gets a tool to determine how various scenarios (what-ifs) might play out (See Figure 1).</blockquote>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="582"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png"
			
			sizes="100vw"
			alt="An example of Counterfactuals"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Figure 2: An example of Counterfactuals using a what-if scenario, letting the user see how changing different values of the model’s features can impact outcomes. Image generated using Google Gemini. (<a href='https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/2-example-counterfactuals.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h3 id="pattern-3-the-highlight-reel-for-local-explanations">Pattern 3: The Highlight Reel (For Local Explanations)</h3>

<p>When an AI performs an action on a user’s content (like summarizing a document or identifying faces in photos), the explanation should be visually linked to the source.</p>

<ul>
<li><strong>Heuristic</strong>: Use visual cues like highlighting, outlines, or annotations to connect the explanation directly to the interface element it’s explaining.</li>
</ul>

<blockquote><strong>Example</strong>: An AI tool that summarizes long articles.<br /><br /><strong>AI-Generated Summary Point</strong>:<br />Initial research showed a market gap for sustainable products.<br /><br /><strong>Source in Document</strong>:<br />“...Our Q2 analysis of market trends conclusively demonstrated that <strong>no major competitor was effectively serving the eco-conscious consumer, revealing a significant market gap for sustainable products</strong>...”</blockquote>

<h3 id="pattern-4-the-push-and-pull-visual-for-value-based-explanations">Pattern 4: The Push-and-Pull Visual (for Value-based Explanations)</h3>

<p>For more complex decisions, users might need to understand the interplay of factors. Simple data visualizations can make this clear without being overwhelming.</p>

<ul>
<li><strong>Heuristic</strong>: Use simple, color-coded data visualizations (like bar charts) to show the factors that positively and negatively influenced a decision.</li>
</ul>

<blockquote><strong>Example</strong>: An AI screening a candidate’s profile for a job.<br /><br />Why this candidate is a 75% match:<br /><br /><strong>Factors pushing the score up</strong>:<br /><ul><li>5+ Years UX Research Experience</li><li>Proficient in Python</li></ul><br /><strong>Factors pushing the score down</strong>:<br /><ul><li>No experience with B2B SaaS</li></ul></blockquote>

<p>Learning and using these design patterns in the UX of your AI product will help increase the explainability. You can also use additional techniques that I’m not covering in-depth here. This includes the following:</p>

<ul>
<li><strong>Natural language explanations</strong>: Translating an AI’s technical output into simple, conversational human language that non-experts can easily understand.</li>
<li><strong>Contextual explanations</strong>: Providing a rationale for an AI’s output at the specific moment and location, it is most relevant to the user’s task.</li>
<li><strong>Relevant visualizations</strong>: Using charts, graphs, or heatmaps to visually represent an AI’s decision-making process, making complex data intuitive and easier for users to grasp.</li>
</ul>

<p><strong>A Note For the Front End</strong>: <em>Translating these explainability outputs into seamless user experiences also presents its own set of technical considerations. Front-end developers often grapple with API design to efficiently retrieve explanation data, and performance implications (like the real-time generation of explanations for every user interaction) need careful planning to avoid latency.</em></p>

<h2 id="some-real-world-examples">Some Real-world Examples</h2>

<p><strong>UPS Capital’s DeliveryDefense</strong></p>

<p>UPS uses AI to assign a “delivery confidence score” to addresses to predict the likelihood of a package being stolen. Their <a href="https://about.ups.com/us/en/our-stories/innovation-driven/ups-s-deliverydefense-pits-ai-against-criminals.html">DeliveryDefense</a> software analyzes historical data on location, loss frequency, and other factors. If an address has a low score, the system can proactively reroute the package to a secure UPS Access Point, providing an explanation for the decision (e.g., “Package rerouted to a secure location due to a history of theft”). This system demonstrates how XAI can be used for risk mitigation and building customer trust through transparency.</p>

<p><strong>Autonomous Vehicles</strong></p>

<p>These vehicles of the future will need to effectively use <a href="https://online.hbs.edu/blog/post/ai-in-business">XAI to help their vehicles make safe, explainable decisions</a>. When a self-driving car brakes suddenly, the system can provide a real-time explanation for its action, for example, by identifying a pedestrian stepping into the road. This is not only crucial for passenger comfort and trust but is a regulatory requirement to prove the safety and accountability of the AI system.</p>

<p><strong>IBM Watson Health (and its challenges)</strong></p>

<p>While often cited as a general example of AI in healthcare, it’s also a valuable case study for the <em>importance</em> of XAI. The <a href="https://www.henricodolfing.com/2024/12/case-study-ibm-watson-for-oncology-failure.html">failure of its Watson for Oncology project</a> highlights what can go wrong when explanations are not clear, or when the underlying data is biased or not localized. The system’s recommendations were sometimes inconsistent with local clinical practices because they were based on U.S.-centric guidelines. This serves as a cautionary tale on the need for robust, context-aware explainability.</p>

<h2 id="the-ux-researcher-s-role-pinpointing-and-validating-explanations">The UX Researcher’s Role: Pinpointing And Validating Explanations</h2>

<p>Our design solutions are only effective if they address the right user questions at the right time. An explanation that answers a question the user doesn’t have is just noise. This is where UX research becomes the critical connective tissue in an XAI strategy, ensuring that we explain the what and how that actually matters to our users. The researcher’s role is twofold: first, to inform the strategy by identifying where explanations are needed, and second, to validate the designs that deliver those explanations.</p>

<h3 id="informing-the-xai-strategy-what-to-explain">Informing the XAI Strategy (What to Explain)</h3>

<p>Before we can design a single explanation, we must understand the user’s mental model of the AI system. What do they believe it’s doing? Where are the gaps between their understanding and the system’s reality? This is the foundational work of a UX researcher.</p>

<h4 id="mental-model-interviews-unpacking-user-perceptions-of-ai-systems">Mental Model Interviews: Unpacking User Perceptions Of AI Systems</h4>

<p>Through deep, semi-structured interviews, UX practitioners can gain invaluable insights into how users perceive and understand AI systems. These sessions are designed to encourage users to literally draw or describe their internal “mental model” of how they believe the AI works. This often involves asking open-ended questions that prompt users to explain the system’s logic, its inputs, and its outputs, as well as the relationships between these elements.</p>

<p>These interviews are powerful because they frequently reveal profound misconceptions and assumptions that users hold about AI. For example, a user interacting with a recommendation engine might confidently assert that the system is based purely on their past viewing history. They might not realize that the algorithm also incorporates a multitude of other factors, such as the time of day they are browsing, the current trending items across the platform, or even the viewing habits of similar users.</p>

<p>Uncovering this gap between a user’s mental model and the actual underlying AI logic is critically important. It tells us precisely what specific information we need to communicate to users to help them build a more accurate and robust mental model of the system. This, in turn, is a fundamental step in fostering trust. When users understand, even at a high level, how an AI arrives at its conclusions or recommendations, they are more likely to trust its outputs and rely on its functionality.</p>

<h4 id="ai-journey-mapping-a-deep-dive-into-user-trust-and-explainability">AI Journey Mapping: A Deep Dive Into User Trust And Explainability</h4>

<p>By meticulously mapping the user’s journey with an AI-powered feature, we gain invaluable insights into the precise moments where confusion, frustration, or even profound distrust emerge. This uncovers critical junctures where the user’s mental model of how the AI operates clashes with its actual behavior.</p>

<p>Consider a music streaming service: Does the user’s trust plummet when a playlist recommendation feels “random,” lacking any discernible connection to their past listening habits or stated preferences? This perceived randomness is a direct challenge to the user’s expectation of intelligent curation and a breach of the implicit promise that the AI understands their taste. Similarly, in a photo management application, do users experience significant frustration when an AI photo-tagging feature consistently misidentifies a cherished family member? This error is more than a technical glitch; it strikes at the heart of accuracy, personalization, and even emotional connection.</p>

<p>These pain points are vivid signals indicating precisely where a well-placed, clear, and concise explanation is necessary. Such explanations serve as crucial repair mechanisms, mending a breach of trust that, if left unaddressed, can lead to user abandonment.</p>

<p>The power of AI journey mapping lies in its ability to move us beyond simply explaining the final output of an AI system. While understanding <em>what</em> the AI produced is important, it’s often insufficient. Instead, this process compels us to focus on explaining the <em>process</em> at critical moments. This means addressing:</p>

<ul>
<li><strong>Why a particular output was generated</strong>: Was it due to specific input data? A particular model architecture?</li>
<li><strong>What factors influenced the AI’s decision</strong>: Were certain features weighted more heavily?</li>
<li><strong>How the AI arrived at its conclusion</strong>: Can we offer a simplified, analogous explanation of its internal workings?</li>
<li><strong>What assumptions the AI made</strong>: Were there implicit understandings of the user’s intent or data that need to be surfaced?</li>
<li><strong>What the limitations of the AI are</strong>: Clearly communicating what the AI <em>cannot</em> do, or where its accuracy might waver, builds realistic expectations.</li>
</ul>

<p>AI journey mapping transforms the abstract concept of XAI into a practical, actionable framework for UX practitioners. It enables us to move beyond theoretical discussions of explainability and instead pinpoint the exact moments where user trust is at stake, providing the necessary insights to build AI experiences that are powerful, transparent, understandable, and trustworthy.</p>

<p>Ultimately, research is how we uncover the unknowns. Your team might be debating how to explain why a loan was denied, but research might reveal that users are far more concerned with understanding how their data was used in the first place. Without research, we are simply guessing what our users are wondering.</p>

<h2 id="collaborating-on-the-design-how-to-explain-your-ai">Collaborating On The Design (How to Explain Your AI)</h2>

<p>Once research has identified what to explain, the collaborative loop with design begins. Designers can prototype the patterns we discussed earlier—the “Because” statement, the interactive sliders—and researchers can put those designs in front of users to see if they hold up.</p>

<p><strong>Targeted Usability &amp; Comprehension Testing</strong>: We can design research studies that specifically test the XAI components. We don’t just ask, “*Is this easy to use?*” We ask, “*After seeing this, can you tell me in your own words why the system recommended this product?*” or “*Show me what you would do to see if you could get a different result.*” The goal here is to measure comprehension and actionability, alongside usability.</p>

<p><strong>Measuring Trust Itself</strong>: We can use simple surveys and rating scales before and after an explanation is shown. For instance, we can ask a user on a 5-point scale, “*How much do you trust this recommendation?*” before they see the “Because” statement, and then ask them again afterward. This provides quantitative data on whether our explanations are actually moving the needle on trust.</p>

<p>This process creates a powerful, iterative loop. Research findings inform the initial design. That design is then tested, and the new findings are fed back to the design team for refinement. Maybe the “Because” statement was too jargony, or the “What-If” slider was more confusing than empowering. Through this collaborative validation, we ensure that the final explanations are technically accurate, genuinely understandable, useful, and trust-building for the people using the product.</p>

<h2 id="the-goldilocks-zone-of-explanation">The Goldilocks Zone Of Explanation</h2>

<p>A critical word of caution: it is possible to <em>over-explain</em>. As in the fairy tale, where Goldilocks sought the porridge that was ‘just right’, the goal of a good explanation is to provide the right amount of detail—not too much and not too little. Bombarding a user with every variable in a model will lead to cognitive overload and can actually <em>decrease</em> trust. The goal is not to make the user a data scientist.</p>

<p>One solution is <strong>progressive disclosure</strong>.</p>

<ol>
<li><strong>Start with the simple.</strong> Lead with a concise “Because” statement. For most users, this will be enough.</li>
<li><strong>Offer a path to detail.</strong> Provide a clear, low-friction link like “Learn More” or “See how this was determined.”</li>
<li><strong>Reveal the complexity.</strong> Behind that link, you can offer the interactive sliders, the visualizations, or a more detailed list of contributing factors.</li>
</ol>

<p>This layered approach respects user attention and expertise, providing just the right amount of information for their needs. Let’s imagine you’re using a smart home device that recommends optimal heating based on various factors.</p>

<p><strong>Start with the simple</strong>: “*Your home is currently heated to 72 degrees, which is the optimal temperature for energy savings and comfort.*”</p>

<p><strong>Offer a path to detail</strong>: Below that, a small link or button: “<em>Why is 72 degrees optimal?</em>&ldquo;</p>

<p><strong>Reveal the complexity</strong>: Clicking that link could open a new screen showing:</p>

<ul>
<li>Interactive sliders for outside temperature, humidity, and your preferred comfort level, demonstrating how these adjust the recommended temperature.</li>
<li>A visualization of energy consumption at different temperatures.</li>
<li>A list of contributing factors like “Time of day,” “Current outside temperature,” “Historical energy usage,” and “Occupancy sensors.”</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="449"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png"
			
			sizes="100vw"
			alt="An example of progressive disclosure in three stages"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Figure 3: An example of progressive disclosure in three stages: the simple details with an option to click for more details, more details with the option to understand what will happen if the user changes the settings. (<a href='https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/3-example-progressive-disclosure.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>It’s effective to combine multiple XAI methods and this Goldilocks Zone of Explanation pattern, which advocates for progressive disclosure, implicitly encourages this. You might start with a simple “Because” statement (Pattern 1) for immediate comprehension, and then offer a “Learn More” link that reveals a “What-If” Interactive (Pattern 2) or a “Push-and-Pull Visual” (Pattern 4) for deeper exploration.</p>

<p>For instance, a loan application system could initially state the primary reason for denial (feature importance), then allow the user to interact with a “What-If” tool to see how changes to their income or debt would alter the outcome (counterfactuals), and finally, provide a detailed “Push-and-Pull” chart (value-based explanation) to illustrate the positive and negative contributions of all factors. This layered approach allows users to access the level of detail they need, when they need it, preventing cognitive overload while still providing comprehensive transparency.</p>

<p>Determining which XAI tools and methods to use is primarily a function of thorough UX research. Mental model interviews and AI journey mapping are crucial for pinpointing user needs and pain points related to AI understanding and trust. Mental model interviews help uncover user misconceptions about how the AI works, indicating areas where fundamental explanations (like feature importance or local explanations) are needed. AI journey mapping, on the other hand, identifies critical moments of confusion or distrust in the user’s interaction with the AI, signaling where more granular or interactive explanations (like counterfactuals or value-based explanations) would be most beneficial to rebuild trust and provide agency.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="399"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png"
			
			sizes="100vw"
			alt="An example of a fictitious AI business startup assistant"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Figure 4: An example of a fictitious AI business startup assistant. Here, the AI presents the key factor in how the risk level was determined. When the user asks what would change if they manipulate that factor, the counterfactual statement is shown, confirming the impact of that specific factor in the model. (<a href='https://files.smashing.media/articles/beyond-black-box-practical-xai-ux-practitioners/4-ai-business-startup-assistant.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Ultimately, the <em>best</em> way to choose a technique is to let user research guide your decisions, ensuring that the explanations you design directly address actual user questions and concerns, rather than simply offering technical details for their own sake.</p>

<h2 id="xai-for-deep-reasoning-agents">XAI for Deep Reasoning Agents</h2>

<p>Some of the newest AI systems, known as <a href="https://learn.microsoft.com/en-us/microsoft-copilot-studio/faqs-reasoning">deep reasoning agents</a>, produce an explicit “chain of thought” for every complex task. They do not merely cite sources; they show the logical, step-by-step path they took to arrive at a conclusion. While this transparency provides valuable context, a play-by-play that spans several paragraphs can feel overwhelming to a user simply trying to complete a task.</p>

<p>The principles of XAI, especially the Goldilocks Zone of Explanation, apply directly here. We can curate the journey, using progressive disclosure to show only the final conclusion and the most salient step in the thought process first. Users can then opt in to see the full, detailed, multi-step reasoning when they need to double-check the logic or find a specific fact. This approach respects user attention while preserving the agent’s full transparency.</p>

<h2 id="next-steps-empowering-your-xai-journey">Next Steps: Empowering Your XAI Journey</h2>

<p>Explainability is a fundamental pillar for building <strong>trustworthy and effective AI products</strong>. For the advanced practitioner looking to drive this change within their organization, the journey extends beyond design patterns into advocacy and continuous learning.</p>

<p>To deepen your understanding and practical application, consider exploring resources like the <a href="https://research.ibm.com/blog/ai-explainability-360">AI Explainability 360 (AIX360) toolkit</a> from IBM Research or Google’s <a href="https://pair-code.github.io/what-if-tool/">What-If Tool</a>, which offer interactive ways to explore model behavior and explanations. Engaging with communities like the <a href="https://responsibleaiforum.com">Responsible AI Forum</a> or specific research groups focused on human-centered AI can provide invaluable insights and collaboration opportunities.</p>

<p>Finally, be an advocate for XAI within your own organization. Frame explainability as a strategic investment. Consider a brief pitch to your leadership or cross-functional teams:</p>

<blockquote>“By investing in XAI, we’ll go beyond building trust; we’ll accelerate user adoption, reduce support costs by empowering users with understanding, and mitigate significant ethical and regulatory risks by exposing potential biases. This is good design and smart business.”</blockquote>

<p>Your voice, grounded in practical understanding, is crucial in bringing AI out of the black box and into a collaborative partnership with users.</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Patrick Brosset</author><title>Masonry: Things You Won’t Need A Library For Anymore</title><link>https://www.smashingmagazine.com/2025/12/masonry-things-you-wont-need-library-anymore/</link><pubDate>Tue, 02 Dec 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/12/masonry-things-you-wont-need-library-anymore/</guid><description>CSS Masonry is almost here! Patrick Brosset takes a deep dive into what this long-awaited feature means for web developers and how you could make use of it in your own work.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/12/masonry-things-you-wont-need-library-anymore/" />
              <title>Masonry: Things You Won’t Need A Library For Anymore</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Masonry: Things You Won’t Need A Library For Anymore</h1>
                  
                    
                    <address>Patrick Brosset</address>
                  
                  <time datetime="2025-12-02T10:00:00&#43;00:00" class="op-published">2025-12-02T10:00:00+00:00</time>
                  <time datetime="2025-12-02T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>About 15 years ago, I was working at a company where we built apps for travel agents, airport workers, and airline companies. We also built our own in-house framework for UI components and single-page app capabilities.</p>

<p>We had components for everything: fields, buttons, tabs, ranges, datatables, menus, datepickers, selects, and multiselects. We even had a div component. Our div component was great by the way, it allowed us to do rounded corners on all browsers, which, believe it or not, wasn&rsquo;t an easy thing to do at the time.</p>














<figure class="
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="407"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png"
			
			sizes="100vw"
			alt="Div component, which allows to do rounded corners"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/1-div-component-example.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Our work took place at a point in our history when JS, Ajax, and dynamic HTML were seen as a revolution that brought us into the future. Suddenly, we could update a page dynamically, get data from a server, and avoid having to navigate to other pages, which was seen as slow and flashed a big white rectangle on the screen between the two pages.</p>

<p>There was a phrase, made popular by Jeff Atwood (the founder of StackOverflow), which read:</p>

<blockquote>“Any application that can be written in JavaScript will eventually be written in JavaScript.”<br /><br />&mdash; <a href='https://blog.codinghorror.com/all-programming-is-web-programming/#:~:text=any%20application%20that%C2%A0can%C2%A0be%20written%20in%20JavaScript%2C%C2%A0will%C2%A0eventually%20be%20written%20in%20JavaScript'>Jeff Atwood</a></blockquote>

<p>To us at the time, this felt like a dare to actually go and create those apps. It felt like a blanket approval to do everything with JS.</p>

<p>So we did everything with JS, and we didn’t really take the time to research other ways of doing things. We didn’t really feel the incentive to properly learn what HTML and CSS could do. We didn’t really perceive the web as an evolving app platform in its entirety. We mostly saw it as something we needed to work around, especially when it came to browser support. We could just throw more JS at it to get things done.</p>

<p>Would taking the time to learn more about how the web worked and what was available on the platform have helped me? Sure, I could probably have shaved a bunch of code that wasn’t truly needed. But, at the time, maybe not that much.</p>

<p>You see, browser differences were pretty significant back then. This was a time when Internet Explorer was still the dominant browser, with Firefox being the close second, but starting to lose market share due to Chrome rapidly gaining popularity. Although Chrome and Firefox were quite good at agreeing on web standards, the environments in which our apps were running meant that we had to support IE6 for a long time. Even when we were allowed to support IE8, we still had to deal with a lot of differences between browsers. Not only that, but the web of the time just didn&rsquo;t have that many capabilities built right into the platform.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://gs.statcounter.com/browser-market-share/all/worldwide/2010">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="492"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png"
			
			sizes="100vw"
			alt=""
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://gs.statcounter.com/browser-market-share/all/worldwide/2010'>statcounter</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/2-browser-market-share.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Fast forward to today. Things have changed tremendously. Not only do we have more of these capabilities than ever before, but the rate at which they become available has increased as well.</p>

<p>Let me ask the question again, then: Would taking the time to learn more about how the web works and what is available on the platform help you today? Absolutely yes. Learning to understand and use the web platform today puts you at a huge advantage over other developers.</p>

<p>Whether you work on performance, accessibility, responsiveness, all of them together, or just shipping UI features, if you want to do it as a responsible engineer, knowing the tools that are available to you helps you reach your goals faster and better.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="some-things-you-might-not-need-a-library-for-anymore">Some Things You Might Not Need A Library For Anymore</h2>

<p>Knowing what browsers support today, the question, then, is: What can we ditch? Do we need a div component to do rounded corners in 2025? Of course, we don’t. The <code>border-radius</code> property has been supported by all currently used browsers for more than 15 years at this point. And <code>corner-shape</code> is also coming soon, for even fancier corners.</p>

<p>Let’s take a look at relatively recent features that are now available in all major browsers, and which you can use to replace existing dependencies in your codebase.</p>

<p>The point isn&rsquo;t to immediately ditch all your beloved libraries and rewrite your codebase. As for everything else, you’ll need to take browser support into account first and decide based on other factors specific to your project. The following features are implemented in the three main browser engines (Chromium, WebKit, and Gecko), but you might have different browser support requirements that prevent you from using them right away. Now is still a good time to learn about these features, though, and perhaps plan to use them at some point.</p>

<h3 id="popovers-and-dialogs">Popovers And Dialogs</h3>

<p>The <a href="https://developer.mozilla.org/docs/Web/API/Popover_API">Popover API</a>, the <a href="https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/dialog"><code>&lt;dialog&gt;</code> HTML element</a>, and the <a href="https://developer.mozilla.org/docs/Web/CSS/Reference/Selectors/::backdrop"><code>::backdrop</code> pseudo-element</a> can help you get rid of dependencies on popup, tooltip, and dialog libraries, such as <a href="https://floating-ui.com/">Floating UI</a>, <a href="https://atomiks.github.io/tippyjs/">Tippy.js</a>, <a href="https://tetherjs.dev/docs/welcome/">Tether</a>, or <a href="https://react-tooltip.com/">React Tooltip</a>.</p>

<p>They handle accessibility and focus management for you, out of the box, are highly customizable by using CSS, and can easily be animated.</p>

<h3 id="accordions">Accordions</h3>

<p>The <a href="https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/details"><code>&lt;details&gt;</code> element</a>, its <a href="https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/details#name"><code>name</code> attribute</a> for mutually exclusive elements, and the <a href="https://developer.mozilla.org/docs/Web/CSS/Reference/Selectors/::details-content"><code>::details-content</code></a> pseudo-element remove the need for accordion components like the <a href="https://getbootstrap.com/docs/5.3/components/accordion/">Bootstrap Accordion</a> or the <a href="https://mui.com/material-ui/react-accordion/">React Accordion component</a>.</p>

<p>Just using the platform here means it’s easier for folks who know HTML/CSS to understand your code without having to first learn to use a specific library. It also means you’re immune to breaking changes in the library or the discontinuation of that library. And, of course, it means less code to download and run. Mutually exclusive details elements don’t need JS to open, close, or animate.</p>

<h3 id="css-syntax">CSS Syntax</h3>

<p><a href="https://developer.mozilla.org/docs/Web/CSS/@layer">Cascade layers</a>, for a more organized CSS codebase, <a href="https://developer.mozilla.org/docs/Web/CSS/Reference/Selectors/Nesting_selector">CSS nesting</a>, for more compact CSS, new color functions, <a href="https://developer.mozilla.org/docs/Web/CSS/CSS_colors/Relative_colors">relative colors</a>, and <a href="https://developer.mozilla.org/docs/Web/CSS/color_value/color-mix"><code>color-mix</code></a>, new Maths functions like <a href="https://developer.mozilla.org/docs/Web/CSS/abs"><code>abs()</code></a>, <a href="https://developer.mozilla.org/docs/Web/CSS/sign"><code>sign()</code></a>, <a href="https://developer.mozilla.org/docs/Web/CSS/pow"><code>pow()</code></a> and others help reduce dependencies on <a href="https://css-tricks.com/is-it-time-to-un-sass/">CSS pre-processors</a>, utility libraries like Bootstrap and Tailwind, or even runtime CSS-in-JS libraries.</p>

<p>The game changer <a href="https://developer.mozilla.org/docs/Web/CSS/Reference/Selectors/:has"><code>:has()</code></a>, one of the most requested features for a long time, removes the need for more complicated JS-based solutions.</p>

<h3 id="js-utilities">JS Utilities</h3>

<p>Modern Array methods like <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast"><code>findLast()</code></a>, or <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/at"><code>at()</code></a>, as well as Set methods like <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set/difference"><code>difference()</code></a>, <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set/intersection"><code>intersection()</code></a>, <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set/union"><code>union()</code></a> and others can reduce dependencies on libraries like <a href="https://lodash.com/">Lodash</a>.</p>

<h3 id="container-queries">Container Queries</h3>

<p><a href="https://developer.mozilla.org/docs/Web/CSS/CSS_containment/Container_queries">Container queries</a> make UI components respond to things other than the viewport size, and therefore make them more reusable across different contexts.</p>

<p>No need to use a JS-heavy UI library for this anymore, and no need to use a <a href="https://github.com/GoogleChromeLabs/container-query-polyfill">polyfill</a> either.</p>

<h3 id="layout">Layout</h3>

<p><a href="https://developer.mozilla.org/docs/Web/CSS/CSS_grid_layout">Grid</a>, <a href="https://developer.mozilla.org/docs/Web/CSS/CSS_grid_layout/Subgrid">subgrid</a>, <a href="https://developer.mozilla.org/docs/Learn_web_development/Core/CSS_layout/Flexbox">flexbox</a>, or <a href="https://developer.mozilla.org/docs/Web/CSS/Reference/Properties/columns">multi-column</a> have been around for a long time now, but looking at the <a href="https://2025.stateofcss.com/en-US">results of the State of CSS surveys</a>, it’s clear that developers tend to be very cautious with adopting new things, and wait for a very long time before they do.</p>

<p>These features have been <a href="https://web-platform-dx.github.io/web-features/">Baseline</a> for a long time and you could use them to get rid of dependencies on things like the <a href="https://getbootstrap.com/docs/5.3/layout/grid/">Bootstrap’s grid system</a>, <a href="https://get.foundation/sites/docs/flexbox-utilities.html">Foundation Framework’s flexbox utilities</a>, <a href="https://bulma.io/documentation/grid/fixed-grid/">Bulma fixed grid</a>, <a href="https://materializecss.com/grid.html">Materialize grid</a>, or <a href="https://tailwindcss.com/docs/columns">Tailwind columns</a>.</p>

<p>I’m not saying you should drop your framework. Your team adopted it for a reason, and removing it might be a big project. But looking at what the web platform can offer without a third-party wrapper on top comes with a lot of benefits.</p>

<h2 id="things-you-might-not-need-anymore-in-the-near-future">Things You Might Not Need Anymore In The Near Future</h2>

<p>Now, let’s take a quick look at some of the things you will not need a library for in the near future. That is to say, the things below are not quite ready for mass adoption, but being aware of them and planning for potential later use can be helpful.</p>

<h3 id="anchor-positioning">Anchor Positioning</h3>

<p><a href="https://developer.mozilla.org/docs/Web/CSS/CSS_anchor_positioning">CSS anchor positioning</a> handles the positioning of popovers and tooltips relative to other elements, and takes care of keeping them in view, even when moving, scrolling, or resizing the page.</p>

<p>This is a great complement to the Popover API mentioned before, which will make it even easier to migrate away from more performance-intensive JS solutions.</p>

<h3 id="navigation-api">Navigation API</h3>

<p>The <a href="https://developer.mozilla.org/docs/Web/API/Navigation_API">Navigation API</a> can be used to handle navigation in single-page apps and might be a great complement, or even a replacement, to <a href="https://reactrouter.com/">React Router</a>, <a href="https://nextjs.org/docs/routing/introduction">Next.js routing</a>, or <a href="https://angular.io/guide/router">Angular routing tasks</a>.</p>

<h3 id="view-transitions-api">View Transitions API</h3>

<p>The <a href="https://developer.mozilla.org/docs/Web/API/View_Transition_API">View Transitions API</a> can animate between the different states of a page. On a single-page application, this makes smooth transitions between states very easy, and can help you get rid of animation libraries such as <a href="https://animejs.com/">Anime.js</a>, <a href="https://greensock.com/gsap/">GSAP</a>, or <a href="https://motion.dev/">Motion.dev</a>.</p>

<p>Even better, the API can also be used with multiple-page applications.</p>

<p>Remember earlier, when I said that the reason we built single-page apps at the company where I worked 15 years ago was to avoid the white flash of page reloads when navigating? Had that API been available at the time, we would have been able to achieve beautiful page transition effects without a single-page framework and without a huge initial download of the entire app.</p>

<h3 id="scroll-driven-animations">Scroll-driven Animations</h3>

<p><a href="https://developer.mozilla.org/docs/Web/CSS/CSS_scroll-driven_animations">Scroll-driven animations</a> run on the user’s scroll position, rather than over time, making them a great solution for storytelling and product tours.</p>

<p>Some people <a href="https://gt-era.com/">have gone a bit over the top</a> with it, but when used well, this can be a very effective design tool, and can help get rid of libraries like: <a href="https://scrollrevealjs.org/">ScrollReveal</a>, <a href="https://gsap.com/scroll/">GSAP Scroll</a>, or <a href="https://wowjs.uk/">WOW.js</a>.</p>

<h3 id="customizable-selects">Customizable Selects</h3>

<p>A <a href="https://developer.mozilla.org/docs/Learn_web_development/Extensions/Forms/Customizable_select">customizable select</a> is a normal <code>&lt;select&gt;</code> element that lets you fully customize its appearance and content, while ensuring accessibility and performance benefits.</p>

<p>This has been a long time coming, and a highly requested feature, and it’s amazing to see it come to the web platform soon. With a built-in customizable select, you can finally ditch all this hard-to-maintain JS code for your custom select components.</p>

<h3 id="css-masonry">CSS Masonry</h3>

<p><a href="https://developer.chrome.com/blog/masonry-update">CSS Masonry</a> is another upcoming web platform feature that I want to spend more time on.</p>

<p>With CSS Masonry, you can achieve layouts that are very hard, or even impossible, with flex, grid, or other built-in CSS layout primitives. Developers often resort to using third-party libraries to achieve Masonry layouts, such as the <a href="https://masonry.desandro.com/">Masonry JS library</a>.</p>

<p>But, more on that later. Let’s wrap this point up before moving on to Masonry.</p>

<div class="partners__lead-place"></div>

<h2 id="why-you-should-care">Why You Should Care</h2>

<p>The job market is full of web developers with experience in JavaScript and the latest frameworks of the day. So, really, what’s the point in learning to use the web platform primitives more, if you can do the same things with the libraries, utilities, and frameworks you already know today?</p>

<p>When an entire industry relies on these frameworks, and you can just pull in the right library, shouldn’t browser vendors just work with these libraries to make them load and run faster, rather than trying to convince developers to use the platform instead?</p>

<p>First of all, we do work with library authors, and we do make frameworks better by learning about what they use and improving those areas.</p>

<p>But secondly, “just using the platform” can bring pretty significant benefits.</p>

<h3 id="sending-less-code-to-devices">Sending Less Code To Devices</h3>

<p>The main benefit is that you end up sending far less code to your clients’ devices.</p>

<p>According to the <a href="https://almanac.httparchive.org/en/2024/">2024 Web Almanac</a>, the average number of HTTP requests is around 70 per site, <a href="https://almanac.httparchive.org/en/2024/javascript#how-many-javascript-requests-per-page">most of which is due to JavaScript with 23 requests</a>. In 2024, JS overtook images as the dominant file type too. The median number of page requests for JS files is 23, up 8% since 2022.</p>

<p>And page size continues to grow year over year. The median page weight is around 2MB now, which is 1.8MB more than it was 10 years ago.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://almanac.httparchive.org/en/2024/page-weight">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="462"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png"
			
			sizes="100vw"
			alt="Median page weight"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://almanac.httparchive.org/en/2024/page-weight'>Web Almanac</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/3-median-page-weight.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Sure, your internet connection speed has probably increased, too, but that’s not the case for everyone. And not everyone has the same device capabilities either.</p>

<p>Pulling in third-party code for things you can do with the platform, instead, most probably means you ship more code, and therefore reach fewer customers than you normally would. On the web, bad loading performance leads to large abandonment rates and hurts brand reputation.</p>

<h3 id="running-less-code-on-devices">Running Less Code On Devices</h3>

<p>Furthermore, the code you do ship on your customers’ devices likely runs faster if it uses fewer JavaScript abstractions on top of the platform. It’s also probably more responsive and more accessible by default. All of this leads to more and happier customers.</p>

<p>Check my colleague Alex Russell’s <a href="https://infrequently.org/2024/01/performance-inequality-gap-2024/">yearly performance inequality gap blog</a>, which shows that premium devices are largely absent from markets with billions of users due to wealth inequality. And this gap is only growing over time.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://infrequently.org/2024/01/performance-inequality-gap-2024/#device-performance">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="452"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png"
			
			sizes="100vw"
			alt="Device performance scores"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://infrequently.org/2024/01/performance-inequality-gap-2024/#device-performance'>Infrequently Noted</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/4-device-performance.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="built-in-masonry-layout">Built-in Masonry Layout</h2>

<p>One web platform feature that’s coming soon and which I’m very excited about is CSS Masonry.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="459"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png"
			
			sizes="100vw"
			alt="CSS Masonry"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/5-css-masonry.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Let me start by explaining what Masonry is.</p>

<h3 id="what-is-masonry">What Is Masonry</h3>

<blockquote>Masonry is a type of layout that was made popular by Pinterest years ago. It creates independent tracks of content within which items pack themselves up as close to the start of the track as they can.</blockquote>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="604"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png"
			
			sizes="100vw"
			alt=""
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='pinterest.com'>Pinterest</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/6-pinterest-portfolio.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Many people see Masonry as a great option for portfolios and photo galleries, which it certainly can do. But Masonry is <strong>more flexible</strong> than what you see on Pinterest, and it’s <strong>not limited to just waterfall-like layouts</strong>.</p>

<p>In a Masonry layout:</p>

<ul>
<li>Tracks can be columns or rows:</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png"
			
			sizes="100vw"
			alt="Masonry layout with columns and rows"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/7-layout-columns-rows.png'>Large preview</a>)
    </figcaption>
  
</figure>

<ul>
<li>Tracks of content don’t all have to be the same size:</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="664"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png"
			
			sizes="100vw"
			alt="Masonry layout with tracks of different sizes"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/8-layout-different-sizes.png'>Large preview</a>)
    </figcaption>
  
</figure>

<ul>
<li>Items can span multiple tracks:</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="565"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png"
			
			sizes="100vw"
			alt="Masonry layout with multiple tracks"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/9-layout-multiple-tracks.png'>Large preview</a>)
    </figcaption>
  
</figure>

<ul>
<li>Items can be placed on specific tracks; they don’t have to always follow the automatic placement algorithm:</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="628"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png"
			
			sizes="100vw"
			alt="Masonry layout with items on specific tracks"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/10-layout-items-specific-tracks.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h3 id="demos">Demos</h3>

<p>Here are a few simple demos I made by using the upcoming implementation of CSS Masonry in Chromium.</p>

<p><a href="https://microsoftedge.github.io/Demos/css-masonry/new-york.html">A photo gallery demo</a>, showing how items (the title in this case) can span multiple tracks:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="560"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png"
			
			sizes="100vw"
			alt="A photo gallery demo, showing items on multiple tracks"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/11-photo-gallery-different-sizes.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Another <a href="https://microsoftedge.github.io/Demos/css-masonry/nature.html">photo gallery showing tracks of different sizes</a>:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="437"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png"
			
			sizes="100vw"
			alt="A photo gallery showing tracks of different sizes"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/12-photo-gallery-different-tracks.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>A <a href="https://microsoftedge.github.io/Demos/css-masonry/the-daily-oddity.html">news site layout</a> with some tracks wider than others, and some items spanning the entire width of the layout:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="607"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png"
			
			sizes="100vw"
			alt="A news site layout with some tracks wider than others"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/13-news-site-layout.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>A <a href="https://microsoftedge.github.io/Demos/css-masonry/kanban.html">kanban board</a> showing that items can be placed onto specific tracks:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="320"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png"
			
			sizes="100vw"
			alt="A kanban board with items on specific tracks"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/14-kanban-board.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p><strong>Note</strong>: <em>The previous demos were made with a version of Chromium that’s not yet available to most web users, because CSS Masonry is only just starting to be implemented in browsers.</em></p>

<p>However, web developers have been happily using libraries to create Masonry layouts for years already.</p>

<h3 id="sites-using-masonry-today">Sites Using Masonry Today</h3>

<p>Indeed, Masonry is pretty common on the web today. Here are a few examples I found besides Pinterest:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="458"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png"
			
			sizes="100vw"
			alt="Erik Johansson&#39;s photography site"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://www.erikjo.com/work'>Erik Johansson</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/15-site-masonry.png'>Large preview</a>)
    </figcaption>
  
</figure>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="456"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png"
			
			sizes="100vw"
			alt="Kristian Hammerstad&#39;s site"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://www.kristianhammerstad.com/'>Kristian Hammerstad</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/16-masonry-site.png'>Large preview</a>)
    </figcaption>
  
</figure>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="479"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png"
			
			sizes="100vw"
			alt="L&#39;usine a Gouzou&#39;s catalogue"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://lusineagouzou.fr/catalogue'>L'usine a Gouzou</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/17-masonry-site.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>And a few more, less obvious, examples:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="428"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png"
			
			sizes="100vw"
			alt="Masonry layout from Agora"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      A row-direction Masonry layout from <a href='http://agora.io/en/'>www.agora.io</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/18-masonry-layout.png'>Large preview</a>)
    </figcaption>
  
</figure>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="633"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png"
			
			sizes="100vw"
			alt="Different size tracks from The Free Dictionary"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Different size tracks from <a href='https://www.thefreedictionary.com/'>www.thefreedictionary.com</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/19-different-size-tracks.png'>Large preview</a>)
    </figcaption>
  
</figure>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="605"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png"
			
			sizes="100vw"
			alt="Masonry layout of OneSignal"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Image source: <a href='https://onesignal.com/'>OneSignal</a>. (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/20-masonry-layout.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>So, how were these layouts created?</p>

<h2 id="workarounds">Workarounds</h2>

<p>One trick that I’ve seen used is using a Flexbox layout instead, changing its direction to column, and setting it to wrap.</p>

<p>This way, you can place items of different heights in multiple, independent columns, giving the impression of a Masonry layout:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="578"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png"
			
			sizes="100vw"
			alt="Flexbox layout"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/21-flexbox-layout.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>There are, however, two limitations with this workaround:</p>

<ol>
<li>The order of items is different from what it would be with a real Masonry layout. With Flexbox, items fill the first column first and, when it’s full, then go to the next column. With Masonry, items would stack in whichever track (or column in this case) has more space available.</li>
<li>But also, and perhaps more importantly, this workaround requires that you set a fixed height to the Flexbox container; otherwise, no wrapping would occur.</li>
</ol>

<h2 id="third-party-masonry-libraries">Third-party Masonry Libraries</h2>

<p>For more advanced cases, developers have been using libraries.</p>

<p>The most well-known and popular library for this is simply called <a href="https://masonry.desandro.com/">Masonry</a>, and it gets downloaded about 200,000 times per week <a href="https://www.npmjs.com/package/masonry-layout">according to NPM</a>.</p>

<p>Squarespace also provides a <a href="https://www.beyondspace.studio/blog/squarespace-masonry-gallery-layout-guide#method-2-using-gallery-section">layout component that renders a Masonry layout</a>, for a no-code alternative, and many sites use it.</p>

<p>Both of these options use JavaScript code to place items in the layout.</p>

<div class="partners__lead-place"></div>

<h2 id="built-in-masonry">Built-in Masonry</h2>

<p>I’m really excited that Masonry is now starting to appear in browsers as a built-in CSS feature. Over time, you will be able to use Masonry just like you do Grid or Flexbox, that is, without needing any workarounds or third-party code.</p>

<p>My team at Microsoft has been implementing built-in Masonry support in the Chromium open source project, which Edge, Chrome, and many other browsers are based on. Mozilla was actually the first browser vendor to <a href="https://github.com/w3c/csswg-drafts/issues/4650">propose an experimental implementation of Masonry</a> back in 2020. And <a href="https://webkit.org/blog/15269/help-us-invent-masonry-layouts-for-css-grid-level-3/">Apple has also been very interested</a> in making this new web layout primitive happen.</p>

<p>The work to standardize the feature is also moving ahead, with agreement within the CSS working group about the general direction and even a new display type <a href="https://github.com/w3c/csswg-drafts/issues/12022#issuecomment-3525043825"><code>display: grid-lanes</code></a>.</p>

<p>If you want to learn more about Masonry and track progress, check out my <a href="https://patrickbrosset.com/lab/css-masonry-resources/">CSS Masonry resources</a> page.</p>

<p>In time, when Masonry becomes a Baseline feature, just like Grid or Flexbox, we’ll be able to simply use it and benefit from:</p>

<ul>
<li>Better performance,</li>
<li>Better responsiveness,</li>
<li>Ease of use and simpler code.</li>
</ul>

<p>Let’s take a closer look at these.</p>

<h3 id="better-performance">Better Performance</h3>

<p>Making your own Masonry-like layout system, or using a third-party library instead, means you’ll have to run JavaScript code to place items on the screen. This also means that this code will be <em>render blocking</em>. Indeed, either nothing will appear, or things won’t be in the right places or of the right sizes, until that JavaScript code has run.</p>

<p>Masonry layout is often used for the main part of a web page, which means the code would be making your main content appear later than it could otherwise have, degrading your <a href="https://web.dev/articles/lcp#what-is-lcp">LCP, or Largest Contentful Paint metric</a>, which plays a big role in perceived performance and search engine optimization.</p>

<p>I tested the Masonry JS library with a simple layout and by simulating a slow 4G connection in DevTools. The library is not very big (24KB, 7.8KB gzipped), but it took 600ms to load under my test conditions.</p>

<p>Here is a performance recording showing that long 600ms load time for the Masonry library, and that no other rendering activity happened while that was happening:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="541"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png"
			
			sizes="100vw"
			alt="A performance recording showing 600ms load time for the Masonry library"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/masonry-things-you-wont-need-library-anymore/22-performance-recording.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>In addition, after the initial load time, the downloaded script then needed to be parsed, compiled, and then run. All of which, as mentioned before, was blocking the rendering of the page.</p>

<p>With a built-in Masonry implementation in the browser, we won’t have a script to load and run. The browser engine will just do its thing during the initial page rendering step.</p>

<h3 id="better-responsiveness">Better Responsiveness</h3>

<p>Similar to when a page first loads, resizing the browser window leads to rendering the layout in that page again. At this point, though, if the page is using the Masonry JS library, there’s no need to load the script again, because it’s already here. However, the code that moves items in the right places needs to run.</p>

<p>Now this particular library seems to be pretty fast at doing this when the page loads. However, it animates the items when they need to move to a different place on window resize, and this makes a big difference.</p>

<p>Of course, users don’t spend time resizing their browser windows as much as we developers do. But this animated resizing experience can be pretty jarring and adds to the perceived time it takes for the page to adapt to its new size.</p>

<h3 id="ease-of-use-and-simpler-code">Ease Of Use And Simpler Code</h3>

<p>How easy it is to use a web feature and how simple the code looks are important factors that can make a big difference for your team. They can’t ever be as important as the final user experience, of course, but developer experience impacts maintainability. Using a built-in web feature comes with important benefits on that front:</p>

<ul>
<li>Developers who already know HTML, CSS, and JS will most likely be able to use that feature easily because it’s been designed to integrate well and be consistent with the rest of the web platform.</li>
<li>There’s no risk of breaking changes being introduced in how the feature is used.</li>
<li>There’s almost zero risk of that feature becoming deprecated or unmaintained.</li>
</ul>

<p>In the case of built-in Masonry, because it’s a layout primitive, you use it from CSS, just like Grid or Flexbox, no JS involved. Also, other layout-related CSS properties, such as gap, work as you’d expect them to. There are no tricks or workarounds to know about, and the things you do learn are documented on MDN.</p>

<p>For the Masonry JS lib, initialization is a bit complex: it requires a data attribute with a specific syntax, along with hidden HTML elements to set the column and gap sizes.</p>

<p>Plus, if you want to span columns, you need to include the gap size yourself to avoid problems:</p>

<div class="break-out">
<pre><code class="language-html">&lt;script src="https://unpkg.com/masonry-layout@4.2.2/dist/masonry.pkgd.min.js"&gt;&lt;/script&gt;
&lt;style&gt;
  .track-sizer,
  .item {
    width: 20%;
  }
  .gutter-sizer {
    width: 1rem;
  }
  .item {
    height: 100px;
    margin-block-end: 1rem;
  }
  .item:nth-child(odd) {
    height: 200px;
  }
  .item--width2 {
    width: calc(40% + 1rem);
  }
&lt;/style&gt;

&lt;div class="container"
  data-masonry='{ "itemSelector": ".item", "columnWidth": ".track-sizer", "percentPosition": true, "gutter": ".gutter-sizer" }'&gt;
  &lt;div class="track-sizer"&gt;&lt;/div&gt;
  &lt;div class="gutter-sizer"&gt;&lt;/div&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
  &lt;div class="item item--width2"&gt;&lt;/div&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
  ...
&lt;/div&gt;
</code></pre>
</div>

<p>Let’s compare this to what a built-in Masonry implementation would look like:</p>

<pre><code class="language-html">&lt;style&gt;
  .container {
    display: grid-lanes;
    grid-lanes: repeat(4, 20%);
    gap: 1rem;
  }
  .item {
    height: 100px;
  }
  .item:nth-child(odd) {
    height: 200px;
  }
  .item--width2 {
    grid-column: span 2;
  }
&lt;/style&gt;

&lt;div class="container"&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
  &lt;div class="item item--width2"&gt;&lt;/div&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
  ...
&lt;/div&gt;
</code></pre>

<p>Simpler, more compact code that can just use things like <code>gap</code> and where spanning tracks is done with <code>span 2</code>, just like in grid, and doesn’t require you to calculate the right width that includes the gap size.</p>

<h2 id="how-to-know-what-s-available-and-when-it-s-available">How To Know What’s Available And When It’s Available?</h2>

<p>Overall, the question isn’t really if you should use built-in Masonry over a JS library, but rather <em>when</em>. The Masonry JS library is amazing and has been filling a gap in the web platform for many years, and for many happy developers and users. It has a few drawbacks if you compare it to a built-in Masonry implementation, of course, but those are not important if that implementation isn’t ready.</p>

<p>It’s easy for me to list these cool new web platform features because I work at a browser vendor, and I therefore tend to know what’s coming. But developers often share, survey after survey, that keeping track of new things is hard. <strong>Staying informed is difficult</strong>, and companies don’t always prioritize learning anyway.</p>

<p>To help with this, here are a few resources that provide updates in simple and compact ways so you can get the information you need quickly:</p>

<ul>
<li><a href="https://web-platform-dx.github.io/web-features-explorer/">The Web platform features explorer site</a>:

<ul>
<li>You might be interested in its <a href="https://web-platform-dx.github.io/web-features-explorer/release-notes/october-2025/">release notes</a> page.</li>
<li>And, if you like RSS, check out <a href="https://web-platform-dx.github.io/web-features-explorer/release-notes.xml">the release notes feed</a>, as well as the Baseline <a href="https://web-platform-dx.github.io/web-features-explorer/newly-available.xml">Newly Available</a> and <a href="https://web-platform-dx.github.io/web-features-explorer/widely-available.xml">Widely Available</a> feeds.</li>
</ul></li>
<li><a href="https://webstatus.dev/">The Web Platform Status dashboard</a>:

<ul>
<li>You might like its various <a href="https://webstatus.dev/?q=baseline_date%3A2025-01-01..2025-12-31">Baseline year</a> pages.</li>
</ul></li>
<li><a href="https://chromestatus.com/roadmap">Chrome Platform Status’ roadmap page</a>.</li>
</ul>

<p>If you have a bit more time, you might also be interested in browser vendors’ release notes:</p>

<ul>
<li><a href="https://developer.chrome.com/release-notes">Chrome</a></li>
<li><a href="https://learn.microsoft.com/en-us/microsoft-edge/web-platform/release-notes/">Edge</a></li>
<li><a href="https://www.firefox.com/en-US/releases/">Firefox</a></li>
<li><a href="https://developer.apple.com/documentation/safari-release-notes">Safari</a></li>
</ul>

<p>For even more resources, check out my <a href="https://patrickbrosset.com/lab/navigating-the-web-platform/">Navigating the Web Platform Cheatsheet</a>.</p>

<h2 id="my-thing-is-still-not-implemented">My Thing Is Still Not Implemented</h2>

<p>That’s the other side of the problem. Even if you do find the time, energy, and ways to keep track, there’s still frustration with getting your voice heard and your favorite features implemented.</p>

<p>Maybe you’ve been waiting for years for a specific bug to be resolved, or a specific feature to ship in a browser where it’s still missing.</p>

<p>What I’ll say is <strong>browser vendors do listen</strong>. I’m part of several cross-organization teams where we discuss developer signals and feedback all the time. We look at many different sources of feedback, both internal at each browser vendor and external/public on forums, open source projects, blogs, and surveys. And, we’re always trying to create better ways for developers to share their specific needs and use cases.</p>

<p>So, if you can, please demand more from browser vendors and pressure us to implement the features you need. I get that it takes time, and can also be intimidating (not to mention a high barrier to entry), but it also works.</p>

<p>Here are a few ways you can get your (or your company’s) voice heard: Take the annual <a href="https://stateofjs.com/">State of JS</a>, <a href="https://stateofcss.com/">State of CSS</a>, and <a href="https://stateofhtml.com/">State of HTML</a> surveys. They play a big role in how browser vendors prioritize their work.</p>

<p>If you need a specific standard-based API to be implemented consistently across browsers, consider submitting a proposal at the next <a href="https://github.com/web-platform-tests/interop/">Interop project</a> iteration. It requires more time, but consider how <a href="https://docs.google.com/document/d/1ICqlNtdRXlhIlRuXFr1BRgy68R6Q5AwPv2b4hsIWUMY/edit">Shopify</a> and <a href="https://www.rumvision.com/blog/interop-2026-key-apis-for-sitespeed-and-rum/">RUMvision</a> shared their wish lists for Interop 2026. Detailed information like this can be very useful for browser vendors to prioritize.</p>

<p>For more useful links to influence browser vendors, check out my <a href="https://patrickbrosset.com/lab/navigating-the-web-platform/">Navigating the Web Platform Cheatsheet</a>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>To close, I hope this article has left you with a few things to think about:</p>

<ul>
<li>Excitement for Masonry and other upcoming web features.</li>
<li>A few web features you might want to start using.</li>
<li>A few pieces of custom or 3rd-party code you might be able to remove in favor of built-in features.</li>
<li>A few ways to keep track of what’s coming and influence browser vendors.</li>
</ul>

<p>More importantly, I hope I’ve convinced you of the benefits of using the web platform to its full potential.</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Vitaly Friedman</author><title>Designing For Stress And Emergency</title><link>https://www.smashingmagazine.com/2025/11/designing-for-stress-emergency/</link><pubDate>Mon, 24 Nov 2025 13:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/11/designing-for-stress-emergency/</guid><description>Practical guidelines on designing time-critical products that prevent errors and improve accuracy. Part of the &lt;a href="https://measure-ux.com/">Measure UX &amp;amp; Design Impact&lt;/a> (use the code 🎟 &lt;code>IMPACT&lt;/code> to save 20% off today). With a &lt;a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/">live UX training&lt;/a> starting next week.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/11/designing-for-stress-emergency/" />
              <title>Designing For Stress And Emergency</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Designing For Stress And Emergency</h1>
                  
                    
                    <address>Vitaly Friedman</address>
                  
                  <time datetime="2025-11-24T13:00:00&#43;00:00" class="op-published">2025-11-24T13:00:00+00:00</time>
                  <time datetime="2025-11-24T13:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>No design exists in isolation. As designers, we often imagine specific situations in which people will use our product. It might be indeed quite common &mdash; but there will also be other &mdash; <strong>urgent, frustrating, stressful situations</strong>. And they are the ones that we rarely account for.</p>

<p>So how do we account for such situations? How can we help people <strong>use our products while coping with stress</strong> &mdash; without adding to their cognitive load? Let’s take a closer look.</p>

<h2 id="study-where-your-product-fits-into-people-s-lives">Study Where Your Product Fits Into People’s Lives</h2>

<p>When designing digital products, sometimes we get a bit too attached to our <strong>shiny new features and flows</strong> &mdash; often forgetting the messy reality in which these features and flows have to neatly fit. And often it means 10s of other products, 100s of other tabs, and 1000s of other emails.</p>














<figure class="
  
  
  ">
  
    <a href="https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="600"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg"
			
			sizes="100vw"
			alt="An example of a split screen with two power consumption dashboards on a 22-inch screen."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Design never exists in isolation. It must fit the user’s context and their expectations to do its job. (Image source: <a href='https://seabits.com/engine-and-power-dashboards/'>Engine And Power Dashboard</a>) (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/1-designing-for-stress-and-emergency.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>If your customers have to use a <strong>slightly older machine</strong>, with a <em>smallish</em> 22&rdquo; screen and a lot of background noise, they might use your product differently than you might have imagined, e.g., splitting the screen into halves to see both views at the same time (as displayed above).</p>

<p>Chances are high that our customers will use our product <strong>while doing something else</strong>, often with very little motivation, very little patience, plenty of urgent (and way more important) problems, and an unhealthy dose of stress. And that’s where our product must do its job well.</p>

<h2 id="what-is-stress">What Is Stress?</h2>

<p>What exactly do we mean when we talk about “stress”? As H Locke noted, stress is the <strong>body’s response to a situation it cannot handle</strong>. There is a mismatch between what people can control, their own skills, and the challenge in front of them.</p>

<p>If the situation seems unmanageable and the goal they want to achieve moves further away, it creates an enormous sense of <strong>failing</strong>. It can be extremely frustrating and demotivating.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://alypain.com/5-apps-to-reduce-stress-in-teens/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="804"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg"
			
			sizes="100vw"
			alt="SOS Emergency System"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Stress has many levels. The key is not to let it spiral into dangerous zones. (Image source: <a href='https://alypain.com/5-apps-to-reduce-stress-in-teens/'>Alypain</a>) (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/2-designing-for-stress-and-emergency.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Some failures have a local scope, but many have a <strong>far-reaching impact</strong>. Many people can’t choose the products they have to use for work, so when a tool fails repeatedly, causes frustration, or is unreliable, it affects the worker, the work, the colleagues, and processes within the organization. <strong>Fragility has a high cost</strong> &mdash; and so does frustration.</p>

<h2 id="how-stress-influences-user-interactions">How Stress Influences User Interactions</h2>

<p>It’s not a big surprise: stress disrupts attention, memory, cognition, and decision-making. It makes it difficult to prioritize and draw logical conclusions. In times of stress, we <strong>rely on fast, intuitive judgments</strong>, not reasoning. Typically, it leads to instinctive responses based on established habits.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="535"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png"
			
			sizes="100vw"
			alt="Designing For Stress And Emergency"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Overwhelming products can add to the cognitive load and lead to mistakes. However, people also get used to any products once they’ve used them long enough. (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/3-designing-for-stress-and-emergency.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>When users are in an emergency, they experience <em>cognitive tunneling</em> — it&rsquo;s a state when their peripheral vision narrows, reading comprehension drops, fine motor skills deteriorate, and patience drops sharply. Under pressure, people often make decisions hastily, while others get entirely paralyzed. Either way is a likely <strong>path to mistakes</strong> &mdash; often irreversible ones and often without time for extensive deliberations.</p>

<p>Ideally, these decisions would be made way ahead of time &mdash; and then suggested when needed. But in practice, it’s not always possible. As it turns out, a good way to help people deal with stress is by <strong>providing order</strong> around how they manage it.</p>

<h2 id="single-tasking-instead-of-multi-tasking">Single-Tasking Instead Of Multi-Tasking</h2>

<p><a href="https://consensus.app/search/how-effective-are-people-at-multi-tasking-for-work/9GEx-KC0S8-OhSEgXClnrA/">People can’t <em>really</em> multi-task</a>, especially in very stressful situations or emergencies. Especially with a big chunk of work in front of them, people need some order to make progress, reliably. That’s why simpler pages usually work better than one big complex page.</p>

<p>Order means giving users a <strong>clear plan of action</strong> to complete a task. No distractions, no unnecessary navigation. We ask simple questions and <strong>prompt simple actions</strong>, one after another, one thing at a time.</p>














<figure class="
  
  
  ">
  
    <a href="https://designnotes.blog.gov.uk/2017/04/04/weve-published-the-task-list-pattern/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="607"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png"
			
			sizes="100vw"
			alt="Task list pattern by Gov UK"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Poorly designed products can add to the cognitive load and lead to mistakes. (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/4-designing-for-stress-and-emergency.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>An example of the plan is the <a href="https://designnotes.blog.gov.uk/2017/04/04/weve-published-the-task-list-pattern/">Task List Pattern</a>, invented by fine folks at Gov.uk. We break a task into a <strong>sequence of sub-tasks</strong>, describe them with actionable labels, assign statuses, and track progress.</p>

<p>To support accuracy, we revise <strong>default settings</strong>, values, presets, and actions. Also, the <strong>order of actions</strong> and buttons matters, so we put high-priority things first to make them easier to find. Then we add built-in safeguards (e.g., Undo feature) to prevent irreversible errors.</p>

<div class="partners__lead-place"></div>

<h2 id="supporting-in-emergencies">Supporting In Emergencies</h2>

<p>The most effective help during emergencies is to help people deal with the situation in a well-defined and effective way. That means being prepared for and designing an <strong>emergency mode</strong>, e.g., to activate instant alerts on emergency contacts, distribute pre-assigned tasks, and establish a line of communication.</p>














<figure class="
  
  
  ">
  
    <a href="https://www.redcross.org.au/emergencies/prepare/get-prepared-app/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="851"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg"
			
			sizes="100vw"
			alt="Emergency plan by Rediplan App"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      <a href='https://www.redcross.org.au/emergencies/prepare/get-prepared-app/'>Rediplan App</a> to prepare and act in case of emergencies. (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/5-designing-for-stress-and-emergency.jpg'>Large preview</a>)
    </figcaption>
  
</figure>

<p><a href="https://www.redcross.org.au/emergencies/prepare/get-prepared-app/">Rediplan App</a> by Australian Red Cross is an emergency plan companion that encourages citizens to <strong>prepare their documents and belongings</strong> with a few checklists and actions &mdash; including key contracts, meeting places, and medical information, all in one place.</p>

<h2 id="just-enough-friction">Just Enough Friction</h2>

<p>Not all stress is equally harmful, though. As <a href="https://www.kryshiggins.com/optimal-onboarding-zone/">Krystal Higgins points out</a>, if there is not enough friction when onboarding new users and the experience is <strong>too passive</strong> or users are hand-held even through the most basic tasks, you risk that they won’t realize the <strong>personal value</strong> they gain from the experience and, ultimately, lose interest.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://www.kryshiggins.com/optimal-onboarding-zone/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="459"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png"
			
			sizes="100vw"
			alt="Bell Curve For Optimal User Onboarding"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      We need to find the sweet spot between value realization and friction to create experiences that keep users engaged. (Image source: <a href='https://www.kryshiggins.com/optimal-onboarding-zone/'>Krystal Higgins</a>) (<a href='https://files.smashing.media/articles/designing-for-stress-and-emergency/6-designing-for-stress-and-emergency.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="design-and-test-for-stress-cases">Design And Test For Stress Cases</h2>

<p><strong>Stress cases aren’t edge cases</strong>. We can’t predict the emotional state in which a user comes to our site or uses our product. A person looking for specific information on a hospital website or visiting a debt management website, for example, is most likely already stressed. Now, if the interface is overwhelming, it will only add to their cognitive load.</p>

<p>Stress-testing your product is critical to prevent this from happening. It’s useful to set up an annual day to <strong>stress test your product</strong> and refine emergency responses. It could be as simple as running <a href="https://contentdesign.intuit.com/foundations/content-testing/">content testing</a>, or running tests in a real, noisy, busy environment where users actually work — at peak times.</p>

<p>And in case of emergencies, we need to check if fallbacks work as expected and if the current UX of the product helps people manage failures and exceptional situations well enough.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>Emergencies <em>will</em> happen eventually &mdash; it’s just a matter of time. With good design, we can help <strong>mitigate risk and control damage</strong>, and make it hard to make irreversible mistakes. At its heart, that’s what good UX is exceptionally good at.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<p>People can’t multitask, especially in very stressful situations.</p>

<ul>
<li>Stress <strong>disrupts attention</strong>, memory, cognition, decision-making.</li>
<li>Also, it’s <strong>difficult to prioritize</strong> and draw logical conclusions.</li>
<li>Under stress, we rely on fast, intuitive judgments &mdash; not reasoning.</li>
<li>It leads to instinctive responses based on <strong>established habits</strong>.</li>
</ul>

<p>Goal: Design flows that support focus and high accuracy.</p>

<ul>
<li>Start with better default settings, values, presets, and actions.</li>
<li><strong>High-priority first</strong>: order of actions and buttons matters.</li>
<li>Break complex tasks down into a series of simple steps (10s–30s each).</li>
<li>Add built-in <strong>safeguards</strong> to prevent irreversible errors (Undo).</li>
</ul>

<p>Shift users to single-tasking: ask for one thing at a time.</p>

<ul>
<li><strong>Simpler pages</strong> might work better than one complex page.</li>
<li>Suggest a <strong>step-by-step plan of action</strong> to follow along.</li>
<li>Consider, design, and test flows for emergency responses ahead of time.</li>
<li>Add emergency mode for <strong>instant alerts</strong> and task assignments.</li>
</ul>

<h2 id="meet-how-to-measure-ux-and-design-impact">Meet “How To Measure UX And Design Impact”</h2>

<p>You can find more details on <strong>UX Strategy</strong> in 🪴&nbsp;<a href="https://measure-ux.com/"><strong>Measure UX &amp; Design Impact</strong></a> (8h), a practical guide for designers and UX leads to measure and show your UX impact on business. Use the code 🎟 <code>IMPACT</code> to save 20% off today. <a href="https://measure-ux.com/">Jump to the details</a>.</p>

<figure style="margin-bottom:0;padding-bottom:0" class="article__image">
    <a href="https://measure-ux.com/" title="How To Measure UX and Design Impact, with Vitaly Friedman">
    <img width="900" height="466" style="border-radius: 11px" src="https://files.smashing.media/articles/ux-metrics-video-course-release/measure-ux-and-design-impact-course.png" alt="How to Measure UX and Design Impact, with Vitaly Friedman.">
    </a>
</figure>

<div class="book-cta__inverted"><div class="book-cta" data-handler="ContentTabs" data-mq="(max-width: 480px)"><nav class="content-tabs content-tabs--books"><ul><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">
Video + UX Training</button></a></li><li class="content-tab"><a href="#"><button class="btn btn--small btn--white btn--white--bordered">Video only</button></a></li></ul></nav><div class="book-cta__col book-cta__hardcover content-tab--content"><h3 class="book-cta__title"><span>Video + UX Training</span></h3><span class="book-cta__price"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>495<span class="sup">.00</span></span></span> <span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>799<span class="sup">.00</span></span></span></span></span>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3951439" class="btn btn--full btn--medium btn--text-shadow">
Get Video + UX Training<div></div></a><p class="book-cta__desc">25 video lessons (8h) + <a href="https://smashingconf.com/online-workshops/workshops/vitaly-friedman-impact-design/">Live UX Training</a>.<br>100 days money-back-guarantee.</p></div><div class="book-cta__col book-cta__ebook content-tab--content"><h3 class="book-cta__title"><span>Video only</span></h3><div data-audience="anonymous free supporter" data-remove="true"><span class="book-cta__price" data-handler="PriceTag"><span><span class=""><span class="currency-sign">$</span>&nbsp;<span>250<span class="sup">.00</span></span></span><span class="book-cta__price--old"><span class="currency-sign">$</span>&nbsp;<span>395<span class="sup">.00</span></span></span></span></div>
<a href="https://smart-interface-design-patterns.thinkific.com/enroll/3081832?price_id=3950630" class="btn btn--full btn--medium btn--text-shadow">
Get the video course<div></div></a><p class="book-cta__desc" data-audience="anonymous free supporter" data-remove="true">25 video lessons (8h). Updated yearly.<br>Also available as a <a href="https://smart-interface-design-patterns.thinkific.com/enroll/3082557?price_id=3951421">UX Bundle with 2 video courses.</a></p></div><span></span></div></div>

<h2 id="useful-resources">Useful Resources</h2>

<ul>
<li>“<a href="https://medium.com/design-bootcamp/ux-case-study-standby-17000867133c">Designing The SOS Emergency System</a>”, by Ritik Jayy</li>
<li>“<a href="https://medium.com/net-magazine/designing-for-crisis-9cab10b4c519">Designing For Crisis</a>”, by Eric Meyer</li>
<li>“<a href="https://medium.com/designing-services/designing-for-stressed-out-users-part-1-4489793dbe41">Designing For Stressed Out Users</a>” (Series), by H Locke</li>
<li><a href="https://uxpodcast.com/293-life-death-design-katie-swindler/">Designing For Stress</a> (Podcast), by Katie Swindler</li>
<li><a href="https://www.linkedin.com/posts/vitalyfriedman_ux-design-activity-7167433494200066048-trWE">Designing For Edge Cases and Exceptions</a>, by yours truly</li>
<li><a href="https://dfrlbook.com/"><em>Design For Real Life</em></a>, by Sara Wachter-Boettcher, Eric Mayer</li>
<li>“<a href="https://www.kryshiggins.com/optimal-onboarding-zone/">Optimal Stress Levels For Onboarding</a>, by Krystal Higgins</li>
</ul>

<h3 id="further-reading">Further Reading</h3>

<ul>
<li>“<a href="https://www.smashingmagazine.com/2025/09/how-minimize-environmental-impact-website/">How To Minimize The Environmental Impact Of Your Website</a>”, James Chudley</li>
<li>“<a href="https://www.smashingmagazine.com/2025/10/ai-ux-achieve-more-with-less/">AI In UX: Achieve More With Less</a>”, Paul Boag</li>
<li>“<a href="https://www.smashingmagazine.com/2025/10/how-make-ux-research-hard-to-ignore/">How To Make Your UX Research Hard To Ignore</a>”, Vitaly Friedman</li>
<li>“<a href="https://www.smashingmagazine.com/2025/09/from-prompt-to-partner-designing-custom-ai-assistant/">From Prompt To Partner: Designing Your Custom AI Assistant</a>,” Lyndon Cerejo</li>
</ul>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Andy Clarke</author><title>Smashing Animations Part 6: Magnificent SVGs With `&lt;use>` And CSS Custom Properties</title><link>https://www.smashingmagazine.com/2025/11/smashing-animations-part-6-svgs-css-custom-properties/</link><pubDate>Fri, 07 Nov 2025 15:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/11/smashing-animations-part-6-svgs-css-custom-properties/</guid><description>SVG is one of those web technologies that’s both elegant and, at times, infuriating. In this article, pioneering author and web designer &lt;a href="https://stuffandnonsense.co.uk">Andy Clarke&lt;/a> explains his technique for animating SVG elements that are hidden in the Shadow DOM.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/11/smashing-animations-part-6-svgs-css-custom-properties/" />
              <title>Smashing Animations Part 6: Magnificent SVGs With `&lt;use&gt;` And CSS Custom Properties</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Smashing Animations Part 6: Magnificent SVGs With `&lt;use&gt;` And CSS Custom Properties</h1>
                  
                    
                    <address>Andy Clarke</address>
                  
                  <time datetime="2025-11-07T15:00:00&#43;00:00" class="op-published">2025-11-07T15:00:00+00:00</time>
                  <time datetime="2025-11-07T15:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>I explained recently how I use <code>&lt;symbol&gt;</code>, <code>&lt;use&gt;</code>, and CSS Media Queries to develop what I call <a href="https://www.smashingmagazine.com/2025/10/smashing-animations-part-5-building-adaptive-svgs/">adaptive SVGs</a>. Symbols let us define an element once and then <em>use</em> it again and again, making SVG animations easier to maintain, more efficient, and lightweight.</p>

<p>Since I wrote that explanation, I’ve designed and implemented new <a href="https://stuffandnonsense.co.uk/blog/say-hello-to-my-magnificent-7">Magnificent 7</a> animated graphics across <a href="https://stuffandnonsense.co.uk/">my website</a>. They play on the web design pioneer theme, featuring seven magnificent Old West characters.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://stuffandnonsense.co.uk/">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png"
			
			sizes="100vw"
			alt="Graphics featuring seven magnificent Old West characters"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      View this animated SVG on <a href='https://stuffandnonsense.co.uk/'>my website</a>. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/1-graphics-old-west-characters.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p><code>&lt;symbol&gt;</code> and <code>&lt;use&gt;</code> let me define a character design and reuse it across multiple SVGs and pages. First, I created my characters and put each into a <code>&lt;symbol&gt;</code> inside a hidden library SVG:</p>

<div class="break-out">
<pre><code class="language-svg">&lt;!-- Symbols library --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" style="display:none;"&gt;
 &lt;symbol id="outlaw-1"&gt;[...]&lt;/symbol&gt;
 &lt;symbol id="outlaw-2"&gt;[...]&lt;/symbol&gt;
 &lt;symbol id="outlaw-3"&gt;[...]&lt;/symbol&gt;
 &lt;!-- etc. --&gt;
&lt;/svg&gt;
</code></pre>
</div>

<p>Then, I referenced those symbols in two other SVGs, one for large and the other for small screens:</p>

<pre><code class="language-svg">&lt;!-- Large screens --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" id="svg-large"&gt;
 &lt;use href="outlaw-1" /&gt;
 &lt;!-- ... --&gt;
&lt;/svg&gt;

&lt;!-- Small screens --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" id="svg-small"&gt;
 &lt;use href="outlaw-1" /&gt;
 &lt;!-- ... --&gt;
&lt;/svg&gt;
</code></pre>

<p>Elegant. But then came the infuriating. I could reuse the characters, but couldn’t animate or style them. I added CSS rules targeting elements within the symbols referenced by a <code>&lt;use&gt;</code>, but nothing happened. Colours stayed the same, and things that should move stayed static. It felt like I’d run into an invisible barrier, and I had.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="https://www.smashingconf.com/online-workshops/">Smashing Workshops</a></strong> on <strong>front-end, design &amp; UX</strong>, with practical takeaways, live sessions, <strong>video recordings</strong> and a friendly Q&amp;A. With Brad Frost, Stéph Walter and <a href="https://smashingconf.com/online-workshops/workshops">so many others</a>.</p>
<a data-instant href="smashing-workshops" class="btn btn--green btn--large" style="">Jump to the workshops&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="smashing-workshops" class="feature-panel-image-link">
<div class="feature-panel-image">
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="/images/smashing-cat/cat-scubadiving-panel.svg"
    alt="Feature Panel"
    width="257"
    height="355"
/>

</div>
</a>
</div>
</aside>
</div>

<h2 id="understanding-the-shadow-dom-barrier">Understanding The Shadow DOM Barrier</h2>

<p>When you reference the contents of a <code>symbol</code> with <code>use</code>, a browser creates a copy of it in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM">Shadow DOM</a>. Each <code>&lt;use&gt;</code> instance becomes its own encapsulated copy of the referenced <code>&lt;symbol&gt;</code>, meaning that CSS from outside can’t break through the barrier to style any elements directly. For example, in normal circumstances, this <code>tapping</code> value triggers a CSS animation:</p>

<pre><code class="language-svg">&lt;g class="outlaw-1-foot tapping"&gt;
 &lt;!-- ... --&gt;
&lt;/g&gt;
</code></pre>

<pre><code class="language-css">.tapping {
  animation: tapping 1s ease-in-out infinite;
}
</code></pre>

<p>But when the same animation is applied to a <code>&lt;use&gt;</code> instance of that same foot, nothing happens:</p>

<pre><code class="language-svg">&lt;symbol id="outlaw-1"&gt;
 &lt;g class="outlaw-1-foot"&gt;&lt;!-- ... --&gt;&lt;/g&gt;
&lt;/symbol&gt;

&lt;use href="#outlaw-1" class="tapping" /&gt;
</code></pre>

<pre><code class="language-css">.tapping {
  animation: tapping 1s ease-in-out infinite;
}
</code></pre>

<p>That’s because the <code>&lt;g&gt;</code> inside the <code>&lt;symbol&gt;</code> element is in a protected shadow tree, and the CSS Cascade stops dead at the <code>&lt;use&gt;</code> boundary. This behaviour can be frustrating, but it’s intentional as it ensures that reused symbol content stays consistent and predictable.</p>

<p>While learning how to develop adaptive SVGs, I found all kinds of attempts to work around this behaviour, but most of them sacrificed the reusability that makes SVG so elegant. I didn’t want to duplicate my characters just to make them blink at different times. I wanted a single <code>&lt;symbol&gt;</code> with instances that have their own timings and expressions.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png"
			
			sizes="100vw"
			alt="Several animated elements within a single SVG symbol"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Several animated elements within a single SVG symbol. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/2-animated-elements-single-svg-symbol.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="css-custom-properties-to-the-rescue">CSS Custom Properties To The Rescue</h2>

<p>While working on my pioneer animations, I learned that <strong>regular CSS values can’t cross the boundary into the Shadow DOM, but CSS Custom Properties can</strong>. And even though you can’t directly style elements inside a <code>&lt;symbol&gt;</code>, you can pass custom property values to them. So, when you insert custom properties into an inline style, a browser looks at the cascade, and those styles become available to elements inside the <code>&lt;symbol&gt;</code> being referenced.</p>

<p>I added <code>rotate</code> to an inline style applied to the <code>&lt;symbol&gt;</code> content:</p>

<pre><code class="language-svg">&lt;symbol id="outlaw-1"&gt;
  &lt;g class="outlaw-1-foot" style="
    transform-origin: bottom right; 
    transform-box: fill-box; 
    transform: rotate(var(--foot-rotate));"&gt;
    &lt;!-- ... --&gt;
  &lt;/g&gt;
&lt;/symbol&gt;
</code></pre>

<p>Then, defined the foot tapping animation and applied it to the element:</p>

<pre><code class="language-css">@keyframes tapping {
  0%, 60%, 100% { --foot-rotate: 0deg; }
  20% { --foot-rotate: -5deg; }
  40% { --foot-rotate: 2deg; }
}

use[data-outlaw="1"] {
  --foot-rotate: 0deg;
  animation: tapping 1s ease-in-out infinite;
}
</code></pre>

<h2 id="passing-multiple-values-to-a-symbol">Passing Multiple Values To A Symbol</h2>

<p>Once I’ve set up a symbol to use CSS Custom Properties, I can pass as many values as I want to any <code>&lt;use&gt;</code> instance. For example, I might define variables for <code>fill</code>, <code>opacity</code>, or <code>transform</code>. What’s elegant is that each <code>&lt;symbol&gt;</code> instance can then have its own set of values.</p>

<pre><code class="language-svg">&lt;g class="eyelids" style="
  fill: var(--eyelids-colour, #f7bea1);
  opacity: var(--eyelids-opacity, 1);
  transform: var(--eyelids-scale, 0);"
&gt;
  &lt;!-- etc. --&gt;
&lt;/g&gt;
</code></pre>

<pre><code class="language-css">use[data-outlaw="1"] {
  --eyelids-colour: #f7bea1; 
  --eyelids-opacity: 1;
}

use[data-outlaw="2"] {
  --eyelids-colour: #ba7e5e; 
  --eyelids-opacity: 0;
}
</code></pre>

<p>Support for passing CSS Custom Properties like this is solid, and every contemporary browser handles this behaviour correctly. Let me show you a few ways I’ve been using this technique, starting with a multi-coloured icon system.</p>

<div class="partners__lead-place"></div>

<h2 id="a-multi-coloured-icon-system">A Multi-Coloured Icon System</h2>

<p>When I need to maintain a set of icons, I can define an icon once inside a <code>&lt;symbol&gt;</code> and then use custom properties to apply colours and effects. Instead of needing to duplicate SVGs for every theme, each <code>use</code> can carry its own values.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="167"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png"
			
			sizes="100vw"
			alt="Custom properties for the fill colours in several Bluesky icons"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Custom properties for the fill colours in several Bluesky icons. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/3-custom-properties-colours.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>For example, I applied an <code>--icon-fill</code> custom property for the default <code>fill</code> colour of the <code>&lt;path&gt;</code> in this Bluesky icon :</p>

<pre><code class="language-svg">&lt;symbol id="icon-bluesky"&gt;
  &lt;path fill="var(--icon-fill, currentColor)" d="..." /&gt;
&lt;/symbol&gt;
</code></pre>

<p>Then, whenever I need to vary how that icon looks &mdash; for example, in a <code>&lt;header&gt;</code> and <code>&lt;footer&gt;</code> &mdash; I can pass new <code>fill</code> colour values to each instance:</p>

<pre><code class="language-html">&lt;header&gt;
  &lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
    &lt;use href="#icon-bluesky" style="--icon-fill: #2d373b;" /&gt;
  &lt;/svg&gt;
&lt;/header&gt;

&lt;footer&gt;
  &lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
    &lt;use href="#icon-bluesky" style="--icon-fill: #590d1a;" /&gt;
  &lt;/svg&gt;
&lt;/footer&gt;
</code></pre>

<p>These icons are the same shape but look different thanks to their inline styles.</p>

<h2 id="data-visualisations-with-css-custom-properties">Data Visualisations With CSS Custom Properties</h2>

<p>We can use <code>&lt;symbol&gt;</code> and <code>&lt;use&gt;</code> in plenty more practical ways. They’re also helpful for creating lightweight data visualisations, so imagine an infographic about three famous <a href="https://en.wikipedia.org/wiki/American_frontier">Wild West</a> sheriffs: <a href="https://en.wikipedia.org/wiki/Wyatt_Earp">Wyatt Earp</a>, <a href="https://en.wikipedia.org/wiki/Pat_Garrett">Pat Garrett</a>, and <a href="https://en.wikipedia.org/wiki/Bat_Masterson">Bat Masterson</a>.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="421"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png"
			
			sizes="100vw"
			alt="Data visualisations with CSS Custom Properties"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Data visualisations with CSS Custom Properties. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/4-data-visualisations-css-custom-properties.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Each sheriff’s profile uses the same set of SVG three symbols: one for a bar representing the length of a sheriff’s career, another to represent the number of arrests made, and one more for the number of kills. Passing custom property values to each <code>&lt;use&gt;</code> instance can vary the bar lengths, arrests scale, and kills colour without duplicating SVGs. I first created symbols for those items:</p>

<pre><code class="language-svg">&lt;svg xmlns="http://www.w3.org/2000/svg" style="display:none;"&gt;
  &lt;symbol id="career-bar"&gt;
    &lt;rect
      height="10"
      width="var(--career-length, 100)" 
      fill="var(--career-colour, #f7bea1)"
    /&gt;
  &lt;/symbol&gt;
  
  &lt;symbol id="arrests-badge"&gt;
    &lt;path 
      fill="var(--arrest-color, #d0985f)" 
      transform="scale(var(--arrest-scale, 1))"
    /&gt;
  &lt;/symbol&gt;
  
  &lt;symbol id="kills-icon"&gt;
    &lt;path fill="var(--kill-colour, #769099)" /&gt;
  &lt;/symbol&gt;
&lt;/svg&gt;
</code></pre>

<p>Each symbol accepts one or more values:</p>

<ul>
<li><strong><code>--career-length</code></strong> adjusts the <code>width</code> of the career bar.</li>
<li><strong><code>--career-colour</code></strong> changes the <code>fill</code> colour of that bar.</li>
<li><strong><code>--arrest-scale</code></strong> controls the arrest badge size.</li>
<li><strong><code>--kill-colour</code></strong> defines the <code>fill</code> colour of the kill icon.</li>
</ul>

<p>I can use these to develop a profile of each sheriff using <code>&lt;use&gt;</code> elements with different inline styles, starting with Wyatt Earp.</p>

<div class="break-out">
<pre><code class="language-svg">&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;g id="wyatt-earp"&gt;
    &lt;use href="&#35;career-bar" style="--career-length: 400; --career-color: &#35;769099;"/&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;!-- ... --&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 1;" /&gt;
    &lt;use href="&#35;kills-icon" style="--kill-color: &#35;769099;" /&gt;
  &lt;/g&gt;

  &lt;g id="pat-garrett"&gt;
    &lt;use href="&#35;career-bar" style="--career-length: 300; --career-color: &#35;f7bea1;"/&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;!-- ... --&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 1;" /&gt;
    &lt;use href="&#35;kills-icon" style="--kill-color: &#35;f7bea1;" /&gt;
  &lt;/g&gt;

  &lt;g id="bat-masterson"&gt;
    &lt;use href="#career-bar" style="--career-length: 200; --career-color: &#35;c2d1d6;"/&gt;
    &lt;use href="#arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;!-- ... --&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 2;" /&gt;
    &lt;use href="&#35;arrests-badge" style="--arrest-scale: 1;" /&gt;
    &lt;use href="&#35;kills-icon" style="--kill-color: &#35;c2d1d6;" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;
</code></pre>
</div>

<p>Each <code>&lt;use&gt;</code> shares the same symbol elements, but the inline variables change their colours and sizes. I can even animate those values to highlight their differences:</p>

<pre><code class="language-css">@keyframes pulse {
  0%, 100% { --arrest-scale: 1; }
  50% { --arrest-scale: 1.2; }
}

use[href="#arrests-badge"]:hover {
  animation: pulse 1s ease-in-out infinite;
}
</code></pre>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aCSS%20Custom%20Properties%20aren%e2%80%99t%20only%20helpful%20for%20styling;%20they%20can%20also%20channel%20data%20between%20HTML%20and%20SVG%e2%80%99s%20inner%20geometry,%20binding%20visual%20attributes%20like%20colour,%20length,%20and%20scale%20to%20semantics%20like%20arrest%20numbers,%20career%20length,%20and%20kills.%0a&url=https://smashingmagazine.com%2f2025%2f11%2fsmashing-animations-part-6-svgs-css-custom-properties%2f">
      
CSS Custom Properties aren’t only helpful for styling; they can also channel data between HTML and SVG’s inner geometry, binding visual attributes like colour, length, and scale to semantics like arrest numbers, career length, and kills.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<h2 id="ambient-animations">Ambient Animations</h2>

<p>I started learning to animate elements within symbols while creating the animated graphics for my website’s Magnificent 7. To reduce complexity and make my code lighter and more maintainable, I needed to define each character once and reuse it across SVGs:</p>

<div class="break-out">
<pre><code class="language-svg">&lt;!-- Symbols library --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" style="display:none;"&gt;
  &lt;symbol id="outlaw-1"&gt;[…]&lt;/symbol&gt;
  &lt;!-- ... --&gt;
&lt;/svg&gt;

&lt;!-- Large screens --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" id="svg-large"&gt;
  &lt;use href="outlaw-1" /&gt;
  &lt;!-- ... --&gt;
&lt;/svg&gt;

&lt;!-- Small screens --&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" id="svg-small"&gt;
  &lt;use href="outlaw-1" /&gt;
  &lt;!-- ... --&gt;
&lt;/svg&gt;
</code></pre>
</div>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png"
			
			sizes="100vw"
			alt="My website’s Magnificent 7 characters"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      My website’s Magnificent 7 characters. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/5-characters.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>But I didn’t want those characters to stay static; I needed subtle movements that would bring them to life. I wanted their eyes to blink, their feet to tap, and their moustache whiskers to twitch. So, to animate these details, I pass animation data to elements inside those symbols using CSS Custom Properties, starting with the blinking.</p>

<p>I implemented the blinking effect by placing an SVG group over the outlaws’ eyes and then changing its <code>opacity</code>.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="333"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png"
			
			sizes="100vw"
			alt="Blinking effect by animating eyelids’ opacity."
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Blinking effect by animating eyelids’ opacity. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/6-blinking-effect.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To make this possible, I added an inline style with a CSS Custom Property to the group:</p>

<div class="break-out">
<pre><code class="language-svg">&lt;symbol id="outlaw-1" viewBox="0 0 712 2552"&gt;
 &lt;g class="eyelids" style="opacity: var(--eyelids-opacity, 1);"&gt;
    &lt;!-- ... --&gt;
  &lt;/g&gt;
&lt;/symbol&gt;
</code></pre>
</div>

<p>Then, I defined the blinking animation by changing <code>--eyelids-opacity</code>:</p>

<pre><code class="language-css">@keyframes blink {
  0%, 92% { --eyelids-opacity: 0; }
  93%, 94% { --eyelids-opacity: 1; }
  95%, 97% { --eyelids-opacity: 0.1; }
  98%, 100% { --eyelids-opacity: 0; }
}
</code></pre>

<p>…and applied it to every character:</p>

<div class="break-out">
<pre><code class="language-css">use[data-outlaw] {
  --blink-duration: 4s;
  --eyelids-opacity: 1;
  animation: blink var(--blink-duration) infinite var(--blink-delay);
}
</code></pre>
</div>

<p>…so that each character wouldn’t blink at the same time, I set a different <code>--blink-delay</code> before they all start blinking, by passing another Custom Property:</p>

<pre><code class="language-css">use[data-outlaw="1"] { --blink-delay: 1s; }
use[data-outlaw="2"] { --blink-delay: 2s; }
<!-- ... -->
use[data-outlaw="7"] { --blink-delay: 3s; }
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png"
			
			sizes="100vw"
			alt="Foot tapping effect by animating the foot’s rotation"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Foot tapping effect by animating the foot’s rotation. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/7-foot-tapping-effect.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Some of the characters tap their feet, so I added an inline style with a CSS Custom Property to those groups, too:</p>

<pre><code class="language-svg">&lt;symbol id="outlaw-1" viewBox="0 0 712 2552"&gt;
  &lt;g class="outlaw-1-foot" style="
    transform-origin: bottom right; 
    transform-box: fill-box; 
    transform: rotate(var(--foot-rotate));"&gt;
  &lt;/g&gt;
&lt;/symbol&gt;
</code></pre>

<p>Defining the foot-tapping animation:</p>

<pre><code class="language-css">@keyframes tapping {
  0%, 60%, 100% { --foot-rotate: 0deg; }
  20% { --foot-rotate: -5deg; }
  40% { --foot-rotate: 2deg; }
}
</code></pre>

<p>And adding those extra Custom Properties to the characters’ declaration:</p>

<pre><code class="language-css">use[data-outlaw] {
  --blink-duration: 4s;
  --eyelids-opacity: 1;
  --foot-rotate: 0deg;
  animation: 
    blink var(--blink-duration) infinite var(--blink-delay),
    tapping 1s ease-in-out infinite;
}
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="333"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png"
			
			sizes="100vw"
			alt="Jiggling effect by animating the moustaches’ translation"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Jiggling effect by animating the moustaches’ translation. (<a href='https://files.smashing.media/articles/smashing-animations-part-6-svgs-css-custom-properties/8-jiggling-effect.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>…before finally making the character’s whiskers jiggle via an inline style with a CSS Custom Property which describes how his moustache transforms:</p>

<pre><code class="language-svg">&lt;symbol id="outlaw-1" viewBox="0 0 712 2552"&gt;
  &lt;g class="outlaw-1-tashe" style="
    transform: translateX(var(--jiggle-x, 0px));"
  &gt;
    &lt;!-- ... --&gt;
  &lt;/g&gt;
&lt;/symbol&gt;
</code></pre>

<p>Defining the jiggle animation:</p>

<pre><code class="language-css">@keyframes jiggle {
  0%, 100% { --jiggle-x: 0px; }
  20% { --jiggle-x: -3px; }
  40% { --jiggle-x: 2px; }
  60% { --jiggle-x: -1px; }
  80% { --jiggle-x: 4px; }
}
</code></pre>

<p>And adding those properties to the characters’ declaration:</p>

<pre><code class="language-css">use[data-outlaw] {
  --blink-duration: 4s;
  --eyelids-opacity: 1;
  --foot-rotate: 0deg;
  --jiggle-x: 0px;
  animation: 
    blink var(--blink-duration) infinite var(--blink-delay),
    jiggle 1s ease-in-out infinite,
    tapping 1s ease-in-out infinite;
}
</code></pre>

<p>With these moving parts, the characters come to life, but my markup remains remarkably lean. By combining several animations into a single declaration, I can choreograph their movements without adding more elements to my SVG. Every outlaw shares the same base <code>&lt;symbol&gt;</code>, and their individuality comes entirely from CSS Custom Properties.</p>

<div class="partners__lead-place"></div>

<h2 id="pitfalls-and-solutions">Pitfalls And Solutions</h2>

<p>Even though this technique might seem bulletproof, there are a few traps it’s best to avoid:</p>

<ul>
<li><strong>CSS Custom Properties only work if they’re referenced with a <code>var()</code> inside a <code>&lt;symbol&gt;</code>.</strong> Forget that, and you’ll wonder why nothing updates. Also, properties that aren’t naturally inherited, like <code>fill</code> or <code>transform</code>, need to use <code>var()</code> in their value to benefit from the cascade.</li>
<li><strong>It’s always best to include a fallback value alongside a custom property</strong>, like <code>opacity: var(--eyelids-opacity, 1);</code> to ensure SVG elements render correctly even without custom property values applied.</li>
<li><strong>Inline styles set via the <code>style</code> attribute take precedence</strong>, so if you mix inline and external CSS, remember that Custom Properties follow normal cascade rules.</li>
<li><strong>You can always use DevTools to inspect custom property values.</strong> Select a <code>&lt;use&gt;</code> instance and check the Computed Styles panel to see which custom properties are active.</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>The <code>&lt;symbol&gt;</code> and <code>&lt;use&gt;</code> elements are among the most elegant but sometimes frustrating aspects of SVG. The Shadow DOM barrier makes animating them trickier, but <strong>CSS Custom Properties act as a bridge</strong>. They let you pass colour, motion, and personality across that invisible boundary, resulting in cleaner, lighter, and, best of all, fun animations.</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Daniel Schwarz</author><title>How To Leverage Component Variants In Penpot</title><link>https://www.smashingmagazine.com/2025/11/how-leverage-component-variants-penpot/</link><pubDate>Tue, 04 Nov 2025 10:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/11/how-leverage-component-variants-penpot/</guid><description>With component variants, design systems become more flexible, letting you reuse the same component while adapting its look or state with ease. In this article, Daniel Schwarz demonstrates how design tokens can be leveraged to manage components and their variations using &lt;a href="https://penpot.app?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants">Penpot&lt;/a>, the open-source tool built for scalable, consistent design.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/11/how-leverage-component-variants-penpot/" />
              <title>How To Leverage Component Variants In Penpot</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>How To Leverage Component Variants In Penpot</h1>
                  
                    
                    <address>Daniel Schwarz</address>
                  
                  <time datetime="2025-11-04T10:00:00&#43;00:00" class="op-published">2025-11-04T10:00:00+00:00</time>
                  <time datetime="2025-11-04T10:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                <p>This article is sponsored by <b>Penpot</b></p>
                

<p>Since Brad Frost popularized the use of design systems in digital design <a href="https://bradfrost.com/blog/post/atomic-web-design/">way back in 2013</a>, they’ve become an invaluable resource for organizations &mdash; and even individuals &mdash; that want to craft reusable design patterns that look and feel consistent.</p>

<p>But Brad didn’t just popularize design systems; he also gave us a <strong>framework</strong> for structuring them, and while we don’t have to follow that framework exactly (most people adapt it to their needs), a particularly important part of most design systems is the <strong>variants</strong>, which are <em>variations</em> of components. Component variants allow for the design of components that are the same as other components, but different, so that they’re understood by users immediately, yet provide clarity for a unique context.</p>

<p>This makes component variants just as important as the components themselves. They ensure that we aren’t creating too many components that have to be individually managed, even if they’re only mildly different from other components, and since component variants are grouped together, they also ensure organization and visual consistency.</p>

<p>And now we can use them in <a href="https://penpot.app?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants">Penpot</a>, the web-based, open-source design tool where design is expressed as code. In this article, you’ll learn about variants, their place in <a href="https://penpot.app/design/design-systems?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants">design systems</a>, and how to use them effectively in Penpot.</p>

<h2 id="step-1-get-your-design-tokens-in-order">Step 1: Get Your Design Tokens In Order</h2>

<p>For the most part, what separates one variant from another is the <a href="https://penpot.app/collaboration/design-tokens?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=DesignTokens">design tokens</a> that it uses. But what is a design token exactly?</p>

<p>Imagine a brand color, let’s say a color value equal to <code>hsl(270 100 42)</code> in CSS. We save it as a “design token” called <code>color.brand.default</code> so that we can reuse it more easily without having to remember the more cumbersome <code>hsl(270 100 42)</code>.</p>

<p>From there, we might also create a second design token called <code>background.button.primary.default</code> and set it to <code>color.brand.default</code>, thereby making them equal to the same color, but with different names to establish semantic separation between the two. This referencing the value of one token from another token is often called an “alias”.</p>

<p>This setup gives us the flexibility to change the value of the color document-wide, change the color used in the component (maybe by switching to a different token alias), or create a variant of the component that uses a different color. Ultimately, the goal is to be able to make changes in many places at once rather than one-by-one, mostly by editing the design token values rather than the design itself, at specific scopes rather than limiting ourselves to all-or-nothing changes. This also enables us to scale our design system without constraints.</p>

<p>With that in mind, here’s a rough idea of just a few color-related design tokens for a primary button with hover and disabled states:</p>

<table class="tablesaw break-out">
    <thead>
        <tr>
            <th>Token name</th>
            <th>Token value</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>color.brand.default</code></td>
            <td><code>hsl(270 100 42)</code></td>
        </tr>
        <tr>
            <td><code>color.brand.lighter</code></td>
            <td><code>hsl(270 100 52)</code></td>
        </tr>
        <tr>
            <td><code>color.brand.lightest</code></td>
            <td><code>hsl(270 100 95)</code></td>
        </tr>
    <tr>
            <td><code>color.brand.muted</code></td>
            <td><code>hsl(270 5 50)</code></td>
        </tr>
    <tr>
            <td><code>background.button.primary.default</code></td>
            <td><code>{color.brand.default}</code></td>
        </tr>
    <tr>
            <td><code>background.button.primary.hover</code></td>
            <td><code>{color.brand.lighter}</code></td>
        </tr>
    <tr>
            <td><code>background.button.primary.disabled</code></td>
            <td><code>{color.brand.muted}</code></td>
        </tr>
    <tr>
            <td><code>text.button.primary.default</code></td>
            <td><code>{color.brand.lightest}</code></td>
        </tr>
    <tr>
            <td><code>text.button.primary.hover</code></td>
            <td><code>{color.brand.lightest}</code></td>
        </tr>
     <tr>
            <td><code>text.button.primary.disabled</code></td>
            <td><code>{color.brand.lightest}</code></td>
        </tr>
    </tbody>
</table>

<p>To create a color token in Penpot, switch to the “Tokens” tab in the left panel, click on the plus (<code>+</code>) icon next to “Color”, then specify the name, value, and optional description.</p>

<p>For example:</p>

<ul>
<li><strong>Name</strong>: <code>color.brand.default</code>,</li>
<li><strong>Value</strong>: <code>hsl(270 100 42)</code> (there’s a color picker if you need it).</li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png"
			
			sizes="100vw"
			alt="Creating a color token in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Creating a color token in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/1-color-token-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>It’s pretty much the same process for other types of design tokens.</p>

<p>Don’t worry, I’m not going to walk you through every design token, but I will show you how to create a design token <em>alias</em>. Simply repeat the steps above, but for the value, notice how I’ve just referenced another color token (make sure to include the curly braces):</p>

<ul>
<li><strong>Name</strong>: <code>background.button.primary.default</code>,</li>
<li><strong>Value</strong>: <code>{color.brand.default}</code></li>
</ul>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png"
			
			sizes="100vw"
			alt="Creating a design token alias in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Creating a design token alias in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/2-design-token-alias-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Now, if the value of the color changes, so will the background of the buttons. But also, if we want to decouple the color from the buttons, all we need to do is reference a different color token or value. Mikołaj Dobrucki goes into a lot more detail in another <a href="https://www.smashingmagazine.com/2025/05/integrating-design-code-native-design-tokens-penpot/">Smashing article</a>, but it’s worth noting here that Penpot design tokens are platform-agnostic. They follow the standardized <a href="https://www.w3.org/community/design-tokens/">W3C DTCG format</a>, which means that they’re compatible with other tools and easily export to all platforms, including web, iOS, and Android.</p>

<p>In the next couple of steps, we’ll create a button component and its variants while plugging different design tokens into different variants. You’ll see why doing this is so useful and how using design tokens in variants benefits design systems overall.</p>

<h2 id="step-2-create-the-component">Step 2: Create The Component</h2>

<p>You’ll need to create what’s called a “main” component, which is the one that you’ll update as needed going forward. Other components &mdash; the ones that you’ll actually insert into your designs &mdash; will be copies (or “instances”) of the main component, which is sort of the point, right? Update once, and the changes reflect everywhere.</p>

<p>Here’s one I made earlier, minus the colors:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png"
			
			sizes="100vw"
			alt="Main component"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/3-main-component-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To apply a design token, make sure that you’re on the “Tokens” tab and have the relevant layer selected, then select the design token that you want to apply to it:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png"
			
			sizes="100vw"
			alt="Applying a design token in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Applying a design token in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/4-design-token-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>It doesn’t matter which variant you create first, but you’ll probably want to go with the default one as a starting point, as I’ve done. Either way, to turn this button into a main component, select the button object via the canvas (or “Layers” tab), right-click on it, then choose the “Create component” option from the context menu (or just press <kbd>Ctrl</kbd> / <kbd>⌘</kbd> + <kbd>K</kbd> after selecting it).</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png"
			
			sizes="100vw"
			alt="Creating a component in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Creating a component in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/5-create-component-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Remember to name the component as well. You can do that by double-clicking on the name (also via the canvas or “Layers” tab).</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png"
			
			sizes="100vw"
			alt="Renaming a component in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Renaming a component in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/6-renaming-component-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="step-3-create-the-component-variants">Step 3: Create The Component Variants</h2>

<p>To create a variant, select the main component and either hit the <kbd>Ctrl</kbd> / <kbd>⌘</kbd> + <kbd>K</kbd> keyboard shortcut, or click on the icon that reveals the “Create variant” tooltip (located in the “Design” tab in the right panel).</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png"
			
			sizes="100vw"
			alt="Creating a component variant in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Creating a component variant in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/7-creating-component-variant-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Next, while the variant is still selected, make the necessary design changes via the “Design” tab. Or, if you want to swap design tokens out for other design tokens, you can do that in the same way that you applied them to begin with, via the “Tokens” tab. Rinse and repeat until you have all of your variants on the canvas designed:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png"
			
			sizes="100vw"
			alt="Styling component variants in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Styling component variants in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/8-styling-component-variants-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>After that, as you might’ve guessed, you’ll want to name your variants. But avoid doing this via the “Layers” panel. Instead, select a variant and replace “Property 1” with a label that describes the differentiating property of each variant. Since my button variants in this example represent different states of the same button, I’ve named this “State”. This applies to all of the variants, so you only need to do this once.</p>

<p>Next to the property name, you’ll see “Value 1” or something similar. Edit that for each variant, for example, the name of the state. In my case, I’ve named them “Default”, “Hover”, and “Disabled”.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png"
			
			sizes="100vw"
			alt="Naming component variant properties in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Naming component variant properties in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/9-naming-component-variant-properties-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>And yes, you can add more properties to a component. To do this, click on the nearby plus (<code>+</code>) icon. I’ll talk more about component variants at scale in a minute, though.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png"
			
			sizes="100vw"
			alt="Managing component variant properties in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Managing component variant properties in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/10-managing-component-variant-properties-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To see the component in action, switch to the “Assets” tab (located in the left panel) and drag the component onto the canvas to initialize one instance of it. Again, remember to choose the correct property value from the “Design” tab:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="500"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png"
			
			sizes="100vw"
			alt="Using component variants in Penpot"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Using component variants in Penpot. (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/11-using-component-variants-penpot.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>If you already have a <a href="https://penpot.app/blog/penpot-for-design-systems-101/?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=DesignTokens">Penpot design system</a>, combining multiple components into one component with variants is not only easy and error-proof, but you might be good to go already if you’re using a robust property naming system that uses forward slashes (<code>/</code>). Penpot has put together <a href="https://community.penpot.app/t/how-to-prepare-your-files-for-the-upcoming-variants-release/9804?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=DesignTokens">a very straightforward guide</a>, but the diagram below sums it up pretty well:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="463"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png"
			
			sizes="100vw"
			alt="Diagram on how to prepare your files for the upcoming Variants release"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      (<a href='https://files.smashing.media/articles/how-leverage-component-variants-penpot/12-diagram-sorting.png'>Large preview</a>)
    </figcaption>
  
</figure>

<h2 id="how-component-variants-work-at-scale">How Component Variants Work At Scale</h2>

<p>Design tokens, components, and component variants &mdash; the triple-threat of design systems &mdash; work together, not just to create powerful yet flexible design systems, but sustainable design systems that scale. This is easier to accomplish when thinking ahead, starting with design tokens that separate the “what” from the “what for” using token aliases, despite how verbose that might seem at first.</p>

<p>For example, I used <code>color.brand.lightest</code> for the text color of every variant, but instead of plugging that color token in directly, I created aliases such as <code>text.button.primary.default</code>. This means that I can change the text color of any variant later without having to dive into the actual variant on the canvas, or force a change to <code>color.brand.lightest</code> that might impact a bunch of other components.</p>

<p>Because remember, while the component and its variants give us reusability of the button, <strong>the color tokens give us reusability of the colors</strong>, which might be used in dozens, if not hundreds, of other components. A design system is like a living, breathing ecosystem, where some parts of it are connected, some parts of it aren’t connected, and some parts of it are or aren’t connected but might have to be later, and we need to be ready for that.</p>

<p>The good news is that Penpot makes all of this pretty easy to manage as long as you do a little planning beforehand.</p>

<p>Consider the following:</p>

<ul>
<li>The design tokens that you’ll reuse (e.g., colors, font sizes, and so on),</li>
<li>Where design token aliases will be reused (e.g., buttons, headings, and so on),</li>
<li>Organizing the design tokens into <a href="https://help.penpot.app/user-guide/design-tokens/?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants#design-tokens-sets">sets</a>,</li>
<li>Organizing the sets into <a href="https://help.penpot.app/user-guide/design-tokens/?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants#design-tokens-themes">themes</a>,</li>
<li>Organizing the themes into <a href="https://help.penpot.app/user-guide/design-tokens/?utm_source=SmashingMag&amp;utm_medium=Article&amp;utm_campaign=Variants#design-tokens-themes-group">groups</a>,</li>
<li>The different components that you’ll need, and</li>
<li>The different variants and variant properties that you’ll need for each component.</li>
</ul>

<p>Even the buttons that I designed here today can be scaled far beyond what I’ve already mocked up. Think of all the possible variants that might come up, such as a secondary button color, a tertiary color, a confirmation color, a warning color, a cancelled color, different colors for light and dark mode, not to mention more properties for more states, such as active and focus states. What if we want a whole matrix of variants, like where buttons in a disabled state can be hovered and where all buttons can be focused upon? Or where some buttons have icons instead of text labels, or both?</p>

<p>Designs can get very complicated, but once you’ve organized them into design tokens, components, and component variants in Penpot, they’ll actually feel quite simple, especially once you’re able to see them on the canvas, and even more so once you’ve made a significant change in just a few seconds without breaking anything.</p>

<h2 id="conclusion">Conclusion</h2>

<p>This is how we make component variants work at scale. We get the benefits of <strong>reusability</strong> while keeping the <strong>flexibility</strong> to fork any aspect of our design system, big or small, without breaking out of it. And design tools like Penpot make it possible to not only establish a design system, but also express its design tokens and styles as code.</p>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item><item><author>Andy Clarke</author><title>Ambient Animations In Web Design: Practical Applications (Part 2)</title><link>https://www.smashingmagazine.com/2025/10/ambient-animations-web-design-practical-applications-part2/</link><pubDate>Wed, 22 Oct 2025 13:00:00 +0000</pubDate><guid>https://www.smashingmagazine.com/2025/10/ambient-animations-web-design-practical-applications-part2/</guid><description>Motion can be tricky: too much distracts, too little feels flat. Ambient animations sit in the middle. They’re subtle, slow-moving details that add atmosphere without stealing the show. In part two of his series, web design pioneer &lt;a href="https://stuffandnonsense.co.uk">Andy Clarke&lt;/a> shows how ambient animations can add personality to any website design.</description><content:encoded><![CDATA[
          <html>
            <head>
              <meta charset="utf-8">
              <link rel="canonical" href="https://www.smashingmagazine.com/2025/10/ambient-animations-web-design-practical-applications-part2/" />
              <title>Ambient Animations In Web Design: Practical Applications (Part 2)</title>
            </head>
            <body>
              <article>
                <header>
                  <h1>Ambient Animations In Web Design: Practical Applications (Part 2)</h1>
                  
                    
                    <address>Andy Clarke</address>
                  
                  <time datetime="2025-10-22T13:00:00&#43;00:00" class="op-published">2025-10-22T13:00:00+00:00</time>
                  <time datetime="2025-10-22T13:00:00&#43;00:00" class="op-modified">2026-02-09T03:03:08+00:00</time>
                </header>
                
                

<p>First, a recap:</p>

<blockquote>Ambient animations are the kind of passive movements you might not notice at first. However, they bring a design to life in subtle ways. Elements might subtly transition between colours, move slowly, or gradually shift position. Elements can appear and disappear, change size, or they could rotate slowly, adding depth to a brand’s personality.</blockquote>

<p>In <a href="https://www.smashingmagazine.com/2025/09/ambient-animations-web-design-principles-implementation/">Part 1</a>, I illustrated the concept of ambient animations by recreating the cover of a Quick Draw McGraw comic book as a CSS/SVG animation. But I know not everyone needs to animate cartoon characters, so in Part 2, I’ll share how ambient animation works in three very different projects: Reuven Herman, Mike Worth, and EPD. Each demonstrates how motion can <strong>enhance brand identity</strong>, <strong>personality</strong>, and <strong>storytelling</strong> without dominating a page.</p>

<h2 id="reuven-herman">Reuven Herman</h2>

<p>Los Angeles-based composer Reuven Herman didn’t just want a website to showcase his work. He wanted it to convey his personality and the experience clients have when working with him. Working with musicians is always creatively stimulating: they’re critical, engaged, and full of ideas.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png"
			
			sizes="100vw"
			alt="Design for LA-based composer Reuven Herman"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      My design for LA-based composer Reuven Herman. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/1-design-reuven-herman.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Reuven’s classical and jazz background reminded me of the work of album cover designer <a href="https://stuffandnonsense.co.uk/blog/a-book-for-your-inspiration-collection-alex-steinweiss">Alex Steinweiss</a>.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="267"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png"
			
			sizes="100vw"
			alt="Album cover designs by Alex Steinweiss"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Album cover designs by Alex Steinweiss. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/2-album-cover-designs-alex-steinweiss.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I was inspired by the depth and texture that Alex brought to his designs for over 2,500 unique covers, and I wanted to incorporate his techniques into my illustrations for Reuven.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="267"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png"
			
			sizes="100vw"
			alt="Illustrations for Reuven Herman"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Two of my illustrations for Reuven Herman. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/3-illustrations-reuven-herman.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>To bring Reuven’s illustrations to life, I followed a few core ambient animation principles:</p>

<ul>
<li>Keep animations <strong>slow</strong> and <strong>smooth</strong>.</li>
<li><strong>Loop seamlessly</strong> and avoid abrupt changes.</li>
<li>Use <strong>layering</strong> to build complexity.</li>
<li>Avoid distractions.</li>
<li>Consider <strong>accessibility</strong> and <strong>performance</strong>.</li>
</ul>


<figure class="video-embed-container break-out">
  <div class="video-embed-container--wrapper"
	
  >
    <iframe class="video-embed-container--wrapper-iframe" src="https://player.vimeo.com/video/1129468148"
        frameborder="0"
        allow="autoplay; fullscreen; picture-in-picture"
        allowfullscreen>
    </iframe>
	</div>
	
</figure>

<p>You can view this ambient animation <a href="https://stuffandnonsense.co.uk/lab/ambient-animations.html">in my lab</a>. For Reuven’s site:</p>

<ul>
<li>Sheet music stave lines morph between wavy and straight states.</li>
<li>Notes drift at different speeds to create parallax-like depth.</li>
<li>Piano keys appear to float.</li>
</ul>

<p>My first step is always to <a href="https://www.smashingmagazine.com/2025/06/smashing-animations-part-4-optimising-svgs/">optimise my SVGs for animation</a> by exporting and optimising one set of elements at a time &mdash; always in the order they’ll appear in the final file and building the master SVG gradually. Working forwards from the background, I exported the sheet music stave lines, first in their wavy state.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="275"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png"
			
			sizes="100vw"
			alt="Sheet music stave lines (wavy)"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Sheet music stave lines (wavy). (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/4-sheet-music-stave-lines-wavy.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>…followed by their straight state:</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png"
			
			sizes="100vw"
			alt="Sheet music stave lines (straight)"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Sheet music stave lines (straight). (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/5-sheet-music-stave-lines-straight.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The first step in my animation is to morph the stave lines between states. They’re made up of six paths with multi-coloured strokes. I started with the wavy lines:</p>

<pre><code class="language-svg">&lt;!-- Wavy state --&gt;
&lt;g fill="none" stroke-width="2" stroke-linecap="round"&gt;
&lt;path id="p1" stroke="#D2AB99" d="[…]"/&gt;
&lt;path id="p2" stroke="#BDBEA9" d="[…]"/&gt;
&lt;path id="p3" stroke="#E0C852" d="[…]"/&gt;
&lt;path id="p4" stroke="#8DB38B" d="[…]"/&gt;
&lt;path id="p5" stroke="#43616F" d="[…]"/&gt;
&lt;path id="p6" stroke="#A13D63" d="[…]"/&gt;
&lt;/g&gt;
</code></pre>

<p>Although <a href="https://www.smashingmagazine.com/2023/10/animate-along-path-css/">CSS now enables animation between path points</a>, the number of points in each state needs to match. <a href="https://gsap.com">GSAP</a> doesn’t have that limitation and can animate between states that have different numbers of points, making it ideal for this type of animation. I defined the new set of straight paths:</p>

<pre><code class="language-javascript">&lt;!-- Straight state --&gt;
const Waves = {
  p1: "[…]",
  p2: "[…]",
  p3: "[…]",
  p4: "[…]",
  p5: "[…]",
  p6: "[…]"
};
</code></pre>

<p>Then, I created a <a href="https://gsap.com/docs/v3/GSAP/Timeline">GSAP timeline</a> that repeats backwards and forwards over six seconds:</p>

<pre><code class="language-javascript">const waveTimeline = gsap.timeline({
  repeat: -1,
  yoyo: true,
  defaults: { duration: 6, ease: "sine.inOut" }
});

Object.entries(Waves).forEach(([id, d]) =&gt; {
  waveTimeline.to(`#${id}`, { morphSVG: d }, 0);
});
</code></pre>

<p><strong>Another ambient animation principle is to use layering to build complexity.</strong> Think of it like building a sound mix. You want variation in rhythm, tone, and timing. In my animation, three rows of musical notes move at different speeds:</p>

<pre><code class="language-svg">&lt;path id="notes-row-1"/&gt;
&lt;path id="notes-row-2"/&gt;
&lt;path id="notes-row-3"/&gt;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="275"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png"
			
			sizes="100vw"
			alt="Three rows of musical notes"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Three rows of musical notes. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/6-three-rows-musical-notes.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The duration of each row’s animation is also defined using GSAP, from <code>100</code> to <code>400</code> seconds to give the overall animation a parallax-style effect:</p>

<pre><code class="language-javascript">const noteRows = [
  { id: "#notes-row-1", duration: 300, y: 100 }, // slowest
  { id: "#notes-row-2", duration: 200, y: 250 }, // medium
  { id: "#notes-row-3", duration: 100, y: 400 }  // fastest
];

[…]
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="275"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png"
			
			sizes="100vw"
			alt="Animated shadow"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Animated shadow. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/7-animated-shadow.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The next layer contains a shadow cast by the piano keys, which slowly rotates around its centre:</p>

<pre><code class="language-javascript">gsap.to("shadow", {
  y: -10,
  rotation: -2,
  transformOrigin: "50% 50%",
  duration: 3,
  ease: "sine.inOut",
  yoyo: true,
  repeat: -1
});
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="275"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png"
			
			sizes="100vw"
			alt="Animated piano keys"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Animated piano keys. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/8-animated-piano-keys.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>And finally, the piano keys themselves, which rotate at the same time but in the opposite direction to the shadow:</p>

<pre><code class="language-javascript">gsap.to("#g3-keys", {
  y: 10,
  rotation: 2,
  transformOrigin: "50% 50%",
  duration: 3,
  ease: "sine.inOut",
  yoyo: true,
  repeat: -1
});
</code></pre>

<p>The complete animation can be viewed <a href="https://stuffandnonsense.co.uk/lab/ambient-animations.html">in my lab</a>. By layering motion thoughtfully, the site feels alive without ever dominating the content, which is a perfect match for Reuven’s energy.</p>

<div data-audience="non-subscriber" data-remove="true" class="feature-panel-container">

<aside class="feature-panel" style="">
<div class="feature-panel-left-col">

<div class="feature-panel-description"><p>Meet <strong><a data-instant href="/printed-books/image-optimization/">Image Optimization</a></strong>, Addy Osmani’s new practical guide to optimizing and delivering <strong>high-quality images</strong> on the web. Everything in one single <strong>528-pages</strong> book.</p>
<a data-instant href="https://www.smashingmagazine.com/printed-books/image-optimization/" class="btn btn--green btn--large" style="">Jump to table of contents&nbsp;↬</a></div>
</div>
<div class="feature-panel-right-col"><a data-instant href="https://www.smashingmagazine.com/printed-books/image-optimization/" class="feature-panel-image-link">
<div class="feature-panel-image"><picture><source type="image/avif" srcSet="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/2c669cf1-c6ef-4c87-9901-018b04f7871f/image-optimization-shop-cover-opt.avif" />
<img
    loading="lazy"
    decoding="async"
    class="feature-panel-image-img"
    src="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/87fd0cfa-692e-459c-b2f3-15209a1f6aa7/image-optimization-shop-cover-opt.png"
    alt="Feature Panel"
    width="480"
    height="697"
/>
</picture>
</div>
</a>
</div>
</aside>
</div>

<h2 id="mike-worth">Mike Worth</h2>

<p>As I mentioned earlier, not everyone needs to animate cartoon characters, but I do occasionally. Mike Worth is an Emmy award-winning film, video game, and TV composer who asked me to design his website. For the project, I created and illustrated the character of orangutan adventurer Orango Jones.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png"
			
			sizes="100vw"
			alt="Design for Mike Worth"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      My design for Emmy award-winning composer Mike Worth. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/9-design-mike-worth.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Orango proved to be the perfect subject for ambient animations and features on every page of Mike’s website. He takes the reader on an adventure, and along the way, they get to experience Mike’s music.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png"
			
			sizes="100vw"
			alt="Illustration for Mike Worth"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Another of my illustrations for Mike Worth. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/10-illustration-mike-worth.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>For Mike’s “About” page, I wanted to combine ambient animations with interactions. Orango is in a cave where he has found a stone tablet with faint markings that serve as a navigation aid to elsewhere on Mike’s website. The illustration contains a hidden feature, an easter egg, as when someone presses Orango’s magnifying glass, moving shafts of light stream into the cave and onto the tablet.</p>


<figure class="video-embed-container break-out">
  <div class="video-embed-container--wrapper"
	
  >
    <iframe class="video-embed-container--wrapper-iframe" src="https://player.vimeo.com/video/1129470404"
        frameborder="0"
        allow="autoplay; fullscreen; picture-in-picture"
        allowfullscreen>
    </iframe>
	</div>
	
</figure>

<p>My SVG is deliberately structured, and from back to front, it includes the cave, light shaft, Orango, and navigation:</p>

<pre><code class="language-svg">&lt;svg data-lights="lights-off"&gt;
  &lt;g id="cave"&gt;[…]&lt;/g&gt;
  &lt;path id="light-shaft" d="[…]"&gt;&lt;/path&gt;
  &lt;g id="orango"&gt;[…]&lt;/g&gt;
  &lt;g id="nav"&gt;[…]&lt;/g&gt;
&lt;/svg&gt;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png"
			
			sizes="100vw"
			alt="The cave background"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      The cave background. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/11-cave-background.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>I also added an anchor around a hidden circle, which I positioned over Orango’s magnifying glass, as a large tap target to toggle the light shafts on and off by changing the <code>data-lights</code> value on the SVG:</p>

<div class="break-out">
<pre><code class="language-html">&lt;a href="javascript:void(0);" id="light-switch" title="Lights on/off"&gt;
  &lt;circle cx="700" cy="1000" r="100" opacity="0" /&gt;
&lt;/a&gt;
</code></pre>
</div>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png"
			
			sizes="100vw"
			alt="Orango isolated"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Orango isolated. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/12-orango-isolated.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Then, I added two descendant selectors to my CSS, which adjust the opacity of the light shafts depending on the <code>data-lights</code> value:</p>

<pre><code class="language-css">[data-lights="lights-off"] .light-shaft {
  opacity: .05;
  transition: opacity .25s linear;
}

[data-lights="lights-on"] .light-shaft {
  opacity: .25;
  transition: opacity .25s linear;
}
</code></pre>

<p>A slow and subtle rotation adds natural movement to the light shafts:</p>

<pre><code class="language-css">@keyframes shaft-rotate {
  0% { rotate: 2deg; }
  50% { rotate: -2deg; }
  100% { rotate: 2deg; }
}
</code></pre>

<p>Which is only visible when the light toggle is active:</p>

<pre><code class="language-css">[data-lights="lights-on"] .light-shaft {
  animation: shaft-rotate 20s infinite;
  transform-origin: 100% 0;
}
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png"
			
			sizes="100vw"
			alt="Light shafts isolated"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Light shafts isolated. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/13-light-shafts-isolated.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>When developing any ambient animation, considering performance is crucial, as even though CSS animations are lightweight, features like blur filters and drop shadows can still strain lower-powered devices. It’s also critical to consider accessibility, so <a href="https://www.smashingmagazine.com/2021/10/respecting-users-motion-preferences/">respect someone’s <code>prefers-reduced-motion</code> preferences</a>:</p>

<pre><code class="language-css">@media screen and (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
</code></pre>

<p>When an animation feature is purely decorative, consider adding <code>aria-hidden=&quot;true&quot;</code> to keep it from cluttering up the accessibility tree:</p>

<pre><code class="language-html">&lt;a href="javascript:void(0);" id="light-switch" aria-hidden="true"&gt;
  […]
&lt;/a&gt;
</code></pre>

<p>With Mike’s Orango Jones, ambient animation shifts from subtle atmosphere to playful storytelling. Light shafts and soft interactions weave narrative into the design without stealing focus, proving that animation can support both brand identity and user experience. See this animation <a href="https://stuffandnonsense.co.uk/lab/ambient-animations.html">in my lab</a>.</p>

<div class="partners__lead-place"></div>

<h2 id="epd">EPD</h2>

<p>Moving away from composers, EPD is a property investment company. They commissioned me to design creative concepts for a new website. A quick search for property investment companies will usually leave you feeling underwhelmed by their interchangeable website designs. They include full-width banners with faded stock photos of generic city skylines or ethnically diverse people shaking hands.</p>

<p>For EPD, I wanted to develop a distinctive visual style that the company could own, so I proposed graphic, stylised skylines that reflect both EPD’s brand and its global portfolio. I made them using various-sized circles that recall the company’s logo mark.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="450"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png"
			
			sizes="100vw"
			alt="Design for the property investment company"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      My design for the property investment company EPD. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/14-design-epd.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>The point of an ambient animation is that it doesn’t dominate. It’s a background element and not a call to action. If someone’s eyes are drawn to it, it’s probably too much, so I dial back the animation until it feels like something you’d only catch if you’re really looking. I created three skyline designs, including Dubai, London, and Manchester.</p>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="208"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png"
			
			sizes="100vw"
			alt="Illustrations showing the skylines of Manchester and London"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Manchester and London. Two of my illustrations for EPD. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/15-design-manchester-london.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>In each of these ambient animations, the wheels rotate and the large circles change colour at random intervals.</p>


<figure class="video-embed-container break-out">
  <div class="video-embed-container--wrapper"
	
  >
    <iframe class="video-embed-container--wrapper-iframe" src="https://player.vimeo.com/video/1129472862"
        frameborder="0"
        allow="autoplay; fullscreen; picture-in-picture"
        allowfullscreen>
    </iframe>
	</div>
	
</figure>

<p>To begin optimising this illustration for animation, I exported the base paths containing every element except the wheel:</p>

<pre><code class="language-svg">&lt;g id="banner-base&gt;
  &lt;path d="[…]"/&gt;
  &lt;path d="[…]"/&gt;
  &lt;path d="[…]"/&gt;
  […]
&lt;/g&gt;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="195"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png"
			
			sizes="100vw"
			alt="Manchester illustration base layer"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      My Manchester illustration base layer. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/16-manchester-illustration-base-layer.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Next, I exported a layer containing the <code>circle</code> elements I want to change colour.</p>

<pre><code class="language-svg">&lt;g id="banner-dots"&gt;
  &lt;circle class="data-theme-fill" […]/&gt;
  &lt;circle class="data-theme-fill" […]/&gt;
  &lt;circle class="data-theme-fill" […]/&gt;
  […]
&lt;/g&gt;
</code></pre>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="195"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png"
			
			sizes="100vw"
			alt="Random-looking circles in Manchester illustration"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Random-looking circles in my Manchester illustration. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/17-circles-manchester-illustration.png'>Large preview</a>)
    </figcaption>
  
</figure>

<p>Once again, I used GSAP to select groups of circles that flicker like lights across the skyline:</p>

<div class="break-out">
<pre><code class="language-javascript">function animateRandomDots() {
  const circles = gsap.utils.toArray("#banner-dots circle")
  const numberToAnimate = gsap.utils.random(3, 6, 1)
  const selected = gsap.utils.shuffle(circles).slice(0, numberToAnimate)
}
</code></pre>
</div>

<p>Then, at two-second intervals, the <code>fill</code> colour of those circles changes from the teal accent to the same off-white colour as the rest of my illustration:</p>

<pre><code class="language-javascript">gsap.to(selected, {
  fill: "color(display-p3 .439 .761 .733)",
  duration: 0.3,
  stagger: 0.05,
  onComplete: () =&gt; {
    gsap.to(selected, {
      fill: "color(display-p3 .949 .949 .949)",
      duration: 0.5,
      delay: 2
    })
  }
})

gsap.delayedCall(gsap.utils.random(1, 3), animateRandomDots) }
animateRandomDots()
</code></pre>

<p>The result is a skyline that gently flickers, as if the city itself is alive. Finally, I rotated the wheel. Here, there was no need to use GSAP as this is possible using CSS <code>rotate</code> alone:</p>

<div class="break-out">
<pre><code class="language-svg">&lt;g id="banner-wheel"&gt;
  &lt;path stroke="#F2F2F2" stroke-linecap="round" stroke-width="4" d="[…]"/&gt;
  &lt;path fill="#D8F76E" d="[…]"/&gt;
&lt;/g&gt;
</code></pre>
</div>














<figure class="
  
    break-out article__image
  
  
  ">
  
    <a href="https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png">
    
    <img
      loading="lazy"
      decoding="async"
      fetchpriority="low"
			width="800"
			height="195"
			
			srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png 400w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png 800w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png 1200w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png 1600w,
			        https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png 2000w"
			src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png"
			
			sizes="100vw"
			alt="Rotating wheel in Manchester illustration"
		/>
    
    </a>
  

  
    <figcaption class="op-vertical-bottom">
      Rotating wheel in my Manchester illustration. (<a href='https://files.smashing.media/articles/ambient-animations-web-design-practical-applications-part2/18-rotating-wheel-manchester-illustration.png'>Large preview</a>)
    </figcaption>
  
</figure>

<pre><code class="language-css">
#banner-wheel {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  animation: rotateWheel 30s linear infinite;
}

@keyframes rotateWheel {
  to { transform: rotate(360deg); }
}
</code></pre>

<p>CSS animations are lightweight and ideal for simple, repetitive effects, like fades and rotations. They’re easy to implement and don’t require libraries. GSAP, on the other hand, offers far more control as it can handle path morphing and sequence timelines. The choice of which to use depends on whether I need the <strong>precision of GSAP</strong> or the <strong>simplicity of CSS</strong>.</p>

<p>By keeping the wheel turning and the circles glowing, the skyline animations stay in the background yet give the design a distinctive feel. They avoid stock photo clichés while reinforcing EPD’s brand identity and are proof that, even in a conservative sector like property investment, ambient animation can add atmosphere without detracting from the message.</p>

<div class="partners__lead-place"></div>

<h2 id="wrapping-up">Wrapping up</h2>

<p>From Reuven’s musical textures to Mike’s narrative-driven Orango Jones and EPD’s glowing skylines, these projects show how <strong>ambient animation</strong> adapts to context. Sometimes it’s purely atmospheric, like drifting notes or rotating wheels; other times, it blends seamlessly with interaction, rewarding curiosity without getting in the way.</p>

<p>Whether it echoes a composer’s improvisation, serves as a playful narrative device, or adds subtle distinction to a conservative industry, the same principles hold true:</p>

<blockquote class="pull-quote">
  <p>
    <a class="pull-quote__link" aria-label="Share on Twitter" href="https://twitter.com/share?text=%0aKeep%20motion%20slow,%20seamless,%20and%20purposeful%20so%20that%20it%20enhances,%20rather%20than%20distracts%20from,%20the%20design.%0a&url=https://smashingmagazine.com%2f2025%2f10%2fambient-animations-web-design-practical-applications-part2%2f">
      
Keep motion slow, seamless, and purposeful so that it enhances, rather than distracts from, the design.

    </a>
  </p>
  <div class="pull-quote__quotation">
    <div class="pull-quote__bg">
      <span class="pull-quote__symbol">“</span></div>
  </div>
</blockquote>

<div class="signature">
  <img src="https://www.smashingmagazine.com/images/logo/logo--red.png" alt="Smashing Editorial" width="35" height="46" loading="lazy" decoding="async" />
  <span>(gg, yk)</span>
</div>


              </article>
            </body>
          </html>
        ]]></content:encoded></item></channel></rss>