<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>12 Days of Web</title>
  <subtitle>A year-end celebration of fundamental web technologies: HTML, CSS, and JavaScript.</subtitle>
  <link href="https://12daysofweb.dev/feed.xml" rel="self"/>
  <link href="https://12daysofweb.dev"/>
  <updated>2024-12-24T00:00:00.000Z</updated>
  <id>https://12daysofweb.dev</id>
  <author>
    <name>Stephanie Eckles</name>
  </author>
  <entry>
    <title>CSS margin-trim and line height units</title>
    <link href="https://12daysofweb.dev/2024/css-margin-trim-line-height-units/"/>
    <updated>2024-12-24T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/css-margin-trim-line-height-units/</id>
    <content type="html">



&lt;p&gt;It’s been possible to create gorgeous layouts on the web for decades, but often, refining the details to perfection can take a lot of effort. Arguably too much effort, and developers just don’t have the time. &lt;/p&gt;&lt;p&gt;Happily, the last few years of CSS have seen a lot of new tools, sometimes very simple tools, that when used in a smart fashion suddenly make polishing graphic design details incredibly easy. In this article, I’ll show you two such tools. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;line-height-units&quot;&gt;Line height units&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-margin-trim-line-height-units/#line-height-units&quot; aria-labelledby=&quot;line-height-units&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Gaining a new unit that represents the line height might seem like no big deal. Support &lt;a href=&quot;https://caniuse.com/mdn-css_types_length_lh&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;shipped in every browser in 2023&lt;/a&gt; without much fanfare. But wow, are they powerful.&lt;/p&gt;&lt;p&gt;Basically, &lt;code&gt;1lh&lt;/code&gt; equals the height of one line of text for the current font at the current line height. “LH” stands for Line Height. The accompanying &lt;code&gt;1rlh&lt;/code&gt; unit is the equivalent of one line height at the root, just like how &lt;code&gt;rem&lt;/code&gt; is the &lt;code&gt;em&lt;/code&gt; at the root. “RLH” stands for Root Line Height.&lt;/p&gt;&lt;p&gt;My favorite thing to do with the &lt;code&gt;lh&lt;/code&gt; unit is to set margins on content. Let’s set a new universal margin on paragraphs with the following paragraph rule.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can see the results in the following screenshots. On the left, the margin in the block direction is set to &lt;code&gt;1em&lt;/code&gt;, the default in UA stylesheets since the &amp;#39;90s. On the right it’s changed to &lt;code&gt;1lh&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dwYpbqstJ98wzi_lh1.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;Many people with an eye for layout and spacing can immediately see the difference. You might agree that the version on the right just looks more polished. It looks refined. In comparison, the version on the left looks a bit clunky. It looks, well, like everything on the web has looked for decades. Slightly awkward. &lt;/p&gt;&lt;p&gt;Many other people will look at this comparison and think, “I don’t see it” or “What’s the big deal?” Let’s draw a line grid over the text to make the difference clearer. Hopefully, now it’s more obvious that the blank space between paragraphs is equivalent to a line of text when it’s defined in &lt;code&gt;lh&lt;/code&gt; units.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dwhpbqstJ98wzj_lh2.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;Line height units give us a direct way to tie any size in our layout to the vertical rhythm of the text. Margins are just one possibility — padding is another, as well as gaps, width, height, or any other measurement in the layout.&lt;/p&gt;&lt;p&gt;Line height units are &lt;a href=&quot;https://caniuse.com/mdn-css_types_length_lh&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;supported&lt;/a&gt; in over 90% of the browsers people use today. For that last 10%, you can use progressive enhancement to ensure they get a good experience.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    padding&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* fallback for browsers lh without support */&lt;/span&gt;&lt;br /&gt;    padding&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using this technique causes browsers without support to render &lt;code&gt;1em&lt;/code&gt; of padding, while the browsers with support render &lt;code&gt;1lh&lt;/code&gt; of padding. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;margin-trim&quot;&gt;Margin trim&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-margin-trim-line-height-units/#margin-trim&quot; aria-labelledby=&quot;margin-trim&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now let’s look at the second seemingly-unimportant-but-actually-powerful tool that’s come to CSS — &lt;code&gt;margin-trim&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;Imagine multiple paragraphs inside an article element styled as such.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;margin-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dw3JbqstJ98wzk_lh3.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;By using &lt;code&gt;lh&lt;/code&gt; for the margins between the paragraphs and the padding on the article box, we’re attempting to create a beautiful typographic layout. But what’s happening with all the extra space above and below the text?&lt;/p&gt;&lt;p&gt;Let’s turn on some guides to see better what’s happening. The padding on the article box is seen here in yellow, while the paragraph margins are marked in green. &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dw3ZbqstJ98wzl_lh4.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;Turns out, the margins on the first and last paragraphs (&lt;code&gt;1lh&lt;/code&gt;) are being added to the padding (&lt;code&gt;2lh&lt;/code&gt;) to create a space that measures &lt;code&gt;3lh&lt;/code&gt;. This feels like too much space. &lt;/p&gt;&lt;p&gt;It will be better for the design if we get rid of the margin above the first paragraph and the margin below the last paragraph. The new &lt;code&gt;margin-trim&lt;/code&gt; property gives us an easy way to do so. It provides a mechanism to tell the box, in this case the article, to eliminate any margins that are butting up against that box. &lt;/p&gt;&lt;p&gt;For example: &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Added: */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;margin-trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;margin-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, the browser automatically chops off any margins that touch the edge of the article box in the block direction — in this case, the top and bottom of the box. &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dw3ZbqstJ98wzm_lh5.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;While the margins are defined on the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element, you declare &lt;code&gt;margin-trim&lt;/code&gt; on the &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; element. Here’s the result. It looks pretty great.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dw3pbqstJ98wzn_lh6.png?auto=format,compress&quot; /&gt;&lt;/p&gt;&lt;p&gt;Support for&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/margin-trim&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; margin-trim&lt;/a&gt; shipped almost two years ago in Safari 16.4. So far, Safari is the only &lt;a href=&quot;https://caniuse.com/mdn-css_properties_margin-trim&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;browser with support&lt;/a&gt;. But you can start using it today with progressive enhancement techniques. &lt;/p&gt;&lt;p&gt;What should you do for browsers without support? For our demo, you could write fallback code inside of feature queries, like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;margin-trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;margin-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@support&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;margin-trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token selector&quot;&gt;:first-child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;margin-block-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token selector&quot;&gt;:last-child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;margin-block-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When using &lt;code&gt;:first-child&lt;/code&gt; and &lt;code&gt;:last-child&lt;/code&gt;, any element that’s the first or last direct child of the container will have its margins trimmed. But any content that either isn’t wrapped in an element or that is nested further deep will not.&lt;/p&gt;&lt;p&gt;For example, if the first element is a figure with a top margin, and the figure contains an image that also has a top margin, both of those margins will be trimmed by &lt;code&gt;margin-trim&lt;/code&gt;, while only the figure margin will be trimmed by &lt;code&gt;:first-child&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figure&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;  &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;photo.jxl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[alt]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;[caption]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;margin-trim&lt;/code&gt; property makes trimming such margins easier and more robust than older techniques. &lt;/p&gt;&lt;p&gt;You can, of course, also trim margins that bump up against a box in the inline direction. These are all valid options:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;margin-trim: none&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: block&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: inline&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: block-start&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: block-end&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: inline-start&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;margin-trim: inline-end&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you want to trim in both directions at the same time, you can do so by combining long-hand values. For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;margin-trim: block-start block-end inline-start inline-end&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;More recently, the CSSWG resolved to allow the shorter block and inline keywords in combination, allowing for syntax like this:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;margin-trim: block inline&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Safari still needs to update our implementation to support this last option. Follow &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=284978&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;this issue&lt;/a&gt; for updates.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;try-it-yourself&quot;&gt;Try it yourself&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-margin-trim-line-height-units/#try-it-yourself&quot; aria-labelledby=&quot;try-it-yourself&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You can try out combinations of options to see the effects of both &lt;code&gt;lh&lt;/code&gt; and &lt;code&gt;margin-trim: block&lt;/code&gt; by interacting with this demo.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;YPKZgvX&quot; data-user=&quot;jensimmons&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/jensimmons/pen/YPKZgvX&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;take-your-typography-to-the-next-level&quot;&gt;Take your typography to the next level &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-margin-trim-line-height-units/#take-your-typography-to-the-next-level&quot; aria-labelledby=&quot;take-your-typography-to-the-next-level&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;It really is a great time for typography on the web. Over a dozen small features that shipped in the last few years empower web designers and developers to polish typographic details to a far better result, especially with the kind of easy robustness that makes it practical to accomplish. It’s my hope you use them! &lt;/p&gt;&lt;p&gt;Let me know what you think on &lt;a href=&quot;https://bsky.app/profile/jensimmons.bsky.social&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bluesky&lt;/a&gt; or &lt;a href=&quot;https://front-end.social/@jensimmons&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Mastodon&lt;/a&gt;. I’d love to hear your stories, plans, and questions. &lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://jensimmons.com/&quot;&gt;Jen Simmons&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dvNpbqstJ98wzh_jen-simmons.jpg?auto=format%2Ccompress&amp;rect=0%2C0%2C462%2C462&amp;w=150&amp;h=150&quot; alt=&quot;Jen Simmons&quot; /&gt;
  &lt;p&gt;Jen Simmons is an Apple evangelist for Safari and Webkit and a member of the CSS Working Group.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Jen selected &lt;strong&gt;&lt;a href=&quot;https://www.meaction.net/&quot;&gt;MEAction&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.meaction.net/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/Z2du25bqstJ98wzg_Screenshot2024-12-21at7.43.42PM.png?auto=format,compress&quot; alt=&quot;MEAction&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;MEAction or &quot;Myalgic Encephalomyelitis Action Network&quot; is a patient-led advocacy org for post-viral illness &amp; disability like Long Covid.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>How to Use Baseline Data</title>
    <link href="https://12daysofweb.dev/2024/how-to-use-baseline-data/"/>
    <updated>2024-12-23T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/how-to-use-baseline-data/</id>
    <content type="html">



&lt;p&gt;I’m one of the leads of the &lt;a href=&quot;https://web.dev/baseline&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Baseline initiative&lt;/a&gt; that was started by a team at Google Chrome and is now defined by the &lt;a href=&quot;https://web-platform-dx.github.io/web-features/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Web DX Community Group&lt;/a&gt;. The idea behind Baseline is to make it easier for developers to understand what’s available to use across browsers in a web platform that is changing at a faster rate than ever before. In this post, I will answer the question I’m most often asked, “why doesn’t Baseline consider polyfills or progressive enhancement?” but also demonstrate how Baseline can make the decisions about using polyfills and progressive enhancement much easier.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;why-not-include-polyfills-in-baseline&quot;&gt;Why not include polyfills in Baseline?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/how-to-use-baseline-data/#why-not-include-polyfills-in-baseline&quot; aria-labelledby=&quot;why-not-include-polyfills-in-baseline&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A small group within Chrome thought about the idea that became Baseline for almost two years before an announcement was made. We spent a lot of time looking at research and what developers were actually doing and telling us. We tried to work out the best way to solve this constant issue of it being hard to understand when things on the platform were ready to use.&lt;/p&gt;&lt;p&gt;Initially, we considered a path that included polyfills. We thought it might be possible to have a less conservative version of Baseline that also included things with a solid polyfill. What became quickly apparent, however, was that very few features can be completely polyfilled so that you can just drop in the polyfill and use the feature as specified.&lt;/p&gt;&lt;p&gt;Take container queries, for example. It’s possible to write &lt;a href=&quot;https://developer.chrome.com/blog/inside-the-container-query-polyfill&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a polyfill for container queries&lt;/a&gt;, and in some cases, it will work without causing huge performance issues. You would be likely to hit problems, however, if it were used without &lt;a href=&quot;https://developer.chrome.com/blog/inside-the-container-query-polyfill#best_practices&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;careful consideration&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In addition, polyfills often only cover part of a feature, so to use them, you need to understand what is available. In almost all cases, the answer to the question of whether a polyfill was a good idea for a feature was “it depends.”&lt;/p&gt;&lt;p&gt;The aim of Baseline is to have a clear and objective line for support, so we didn’t pursue the idea of a line that included polyfills. That doesn’t mean we don’t think you should use them, but that the decision needs to be made with an understanding of your project, use case, and audience.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;why-not-include-things-that-are-easy-progressive-enhancements&quot;&gt;Why not include things that are easy progressive enhancements?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/how-to-use-baseline-data/#why-not-include-things-that-are-easy-progressive-enhancements&quot; aria-labelledby=&quot;why-not-include-things-that-are-easy-progressive-enhancements&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Several features are currently newly available that are very straightforward progressive enhancements, for example, &lt;a href=&quot;https://12daysofweb.dev/2024/css-text-wrap/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;text-wrap: balance&lt;/a&gt;. This is the sort of feature where if it isn’t available, nothing bad happens, but those users with the feature get a slightly better experience. &lt;/p&gt;&lt;p&gt;There are other features – &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;subgrid&lt;/a&gt;, for example – that you could allow to fallback to a regular nested grid, thus losing some alignment but leaving things readable for everyone.&lt;/p&gt;&lt;p&gt;The problem with progressive enhancement is that the appetite different people and teams have for it varies. I’ve been telling people for well over twenty years that &lt;a href=&quot;https://web.archive.org/web/20081205022337/http://www.edgeofmyseat.com/blog/it-doesnt-have-to-look-the-same&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;websites do not need to look the same in all browsers&lt;/a&gt;. There are many developers (or their bosses or clients) who very much disagree, even as we approach 2025. This means that any decision around what makes or does not make for good progressive enhancement is entirely subjective. As with polyfills, it also depends on where and how the feature is used.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Both polyfills and progressive enhancement involve decisions we can’t make with availability data.&lt;/p&gt;&lt;p&gt;This discrepancy means I might think it’s absolutely fine to use some feature even if it means some people don’t benefit, whereas your project requirements would mean it can’t be used.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;baseline-reduces-the-number-of-features-you-need-to-make-a-decision-about&quot;&gt;Baseline reduces the number of features you need to make a decision about&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/how-to-use-baseline-data/#baseline-reduces-the-number-of-features-you-need-to-make-a-decision-about&quot; aria-labelledby=&quot;baseline-reduces-the-number-of-features-you-need-to-make-a-decision-about&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Polyfills and progressive enhancement of newly available or limited availability features are probably best left to individual teams to make decisions on. Baseline, however, can still help you here.&lt;/p&gt;&lt;p&gt;For Baseline to work, we first had to understand the web platform as a set of features and then work out the status of those features. This feature grouping work has given us, for the first time, a view of the interoperability of the entire platform. This means we can see how many features are currently &lt;strong&gt;Baseline Newly available&lt;/strong&gt;. At the time of writing, there were &lt;a href=&quot;https://webstatus.dev/?q=baseline_status%3Anewly&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;139 features&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you’ve decided to adopt Baseline Widely available as the point at which you’ll use features, you can feel free to use those features. You can then decide on a case-by-case basis whether to use Newly available features, and because you know exactly which features these are, it’s much easier to do that.&lt;/p&gt;&lt;p&gt;For example, you might want to use the new &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;small, large, and dynamic viewport units&lt;/a&gt;. You can see that they&amp;#39;ve been Baseline Newly available since &lt;a href=&quot;https://webstatus.dev/features/viewport-unit-variants&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the end of December 2022&lt;/a&gt;. If you are just starting work on a brand new project next year, which you don’t intend to ship until the middle of the year, this feature will be widely available by then. This may give you confidence to use it.&lt;/p&gt;&lt;p&gt;Perhaps you’ll consider &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;container queries&lt;/a&gt;, which won’t be Baseline Widely available until August 2025, but feel happy to take the approach explained by Philip Walton in &lt;a href=&quot;https://web.dev/blog/how-to-use-container-queries-now&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How to use container queries now&lt;/a&gt; to offer support to those users with a browser that hasn’t caught up yet. Or you’ll cheerfully use &lt;code&gt;text-wrap: balance&lt;/code&gt;, which won’t be Baseline Widely available until November 2026, acknowledging that it’s just a nice enhancement for those who have it.&lt;/p&gt;&lt;p&gt;What Baseline Newly available gives you is a defined group of features that you know you can use with a little extra care. You know they are interoperable, so they aren’t likely to change. You know that the vast majority of your audience will, in most cases, already have them. You know that as time passes, more of your audience gets the enhanced experience they bring. Importantly, you have a clear date when you can expect the feature to be available pretty much everywhere.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;finding-the-widely-available-date&quot;&gt;Finding the Widely available date&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/how-to-use-baseline-data/#finding-the-widely-available-date&quot; aria-labelledby=&quot;finding-the-widely-available-date&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;On the &lt;a href=&quot;https://webstatus.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Web Platform Status dashboard&lt;/a&gt;, click the &lt;strong&gt;columns&lt;/strong&gt; button and select &lt;strong&gt;Show Baseline status high date&lt;/strong&gt; and &lt;strong&gt;Show Baseline status low date&lt;/strong&gt;. The Baseline low date is when the feature becomes Newly available, and the Baseline High date is Widely available.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2WV8JbqstJ98vfj_baseline.png?auto=format,compress&quot; alt=&quot;Example of modifying the columns settings to show baseline data as described.&quot; /&gt;&lt;figcaption&gt;Customizing the columns shown on the Web Platform Status dashboard.&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-future-of-baseline&quot;&gt;The future of Baseline&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/how-to-use-baseline-data/#the-future-of-baseline&quot; aria-labelledby=&quot;the-future-of-baseline&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Creating the web features data set has been a huge project. As I write this, however, that work is over 80% complete, and the data is available in the &lt;a href=&quot;https://www.npmjs.com/package/web-features&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;npm web-features package&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I believe this dataset will open up so many possibilities for incorporating Baseline into our work. It should allow tooling to be created that helps you know which features you need to consider more carefully. If you could see the Baseline status of any feature in your editor, then you know when you need to make decisions about polyfills or fallback code. I think it would be useful to have a way of identifying things that have become Widely available since being used in a project, to make it easy to remove polyfills that were no longer useful.&lt;/p&gt;&lt;p&gt;We’re already starting to see the first experiments along these lines. For example, the &lt;a href=&quot;https://github.com/tonypconway/bl2bl&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;bl2bl project&lt;/a&gt; turns Baseline thresholds into browserslist configurations. There are so many possibilities, and I’m excited to see what we and the community can create.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://rachelandrew.co.uk/&quot;&gt;Rachel Andrew&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/7358d155-686d-4067-8cdb-949050f65fd5_rachel.jpeg?auto=format%2Ccompress&amp;rect=140%2C39%2C342%2C342&amp;w=150&amp;h=150&quot; alt=&quot;Rachel Andrew&quot; /&gt;
  &lt;p&gt;I’m a web developer and technical writer and editor. I work for Google on the Chrome team as a senior staff technical writer and content lead for &lt;a href=&quot;https://web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev&lt;/a&gt; and &lt;a href=&quot;https://developer.chrome.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;developer.chrome.com&lt;/a&gt;. I’m a member of the CSS Working Group of the W3C, and edit a couple of CSS specifications.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Rachel selected &lt;strong&gt;&lt;a href=&quot;https://www.felinefinefoundation.org.uk/&quot;&gt;Feline Fine Foundation&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.felinefinefoundation.org.uk/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://static.wixstatic.com/media/a03e56_5a09d68d69954e9db629b8a577468ff9~mv2.jpg/v1/fill/w_716,h_242,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/feline%20final%20letterhead.jpg&quot; alt=&quot;Feline Fine Foundation&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;This local charity helps keep cats and their owners together by providing crisis fostering when an owner is made homeless, goes into hospital, or escapes domestic abuse.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>BroadcastChannel API</title>
    <link href="https://12daysofweb.dev/2024/broadcastchannel-api/"/>
    <updated>2024-12-22T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/broadcastchannel-api/</id>
    <content type="html">



&lt;p&gt;State syncing can be tricky to accomplish with web apps, but it&amp;#39;s one of the scenarios improved by using the BroadcastChannel API.&lt;/p&gt;&lt;p&gt;This native web API allows messaging between browsing contexts from the same origin. In other words, if a user has multiple tabs, windows, and even an iframe open from santas-list.tld, use of this API can push messages between all of those contexts. How you handle those messages enables state syncing or other actions.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;sending-and-receiving-broadcast-messages&quot;&gt;Sending and Receiving Broadcast Messages&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/broadcastchannel-api/#sending-and-receiving-broadcast-messages&quot; aria-labelledby=&quot;sending-and-receiving-broadcast-messages&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We&amp;#39;re going to create a simple app for Santa and his elves to track children&amp;#39;s naughty or nice status.&lt;/p&gt;&lt;p&gt;The first step is to set up a broadcast channel. You can name this whatever fits the purpose of your app, and depending on your needs, you can have one channel or multiple.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; santasList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BroadcastChannel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;santasList&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, we can send our first message using the API&amp;#39;s &lt;code&gt;postMessage&lt;/code&gt; method. The content can be a string, as shown, or another data type, like an array or object.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can receive and then respond to the message by adding an event listener to the broadcast channel we set up, listening to the &lt;code&gt;message&lt;/code&gt; event. Any information contained in the message is available in the &lt;code&gt;data&lt;/code&gt; property.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


  
    

    
    &lt;p&gt;We&amp;#39;ll wrap that up in a simple button to test it out. You can do this by opening this article again in a new tab. Then, try pressing the button in one tab and then returning to the other tab to see the message output.&lt;/p&gt;
    

    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Hello World test message&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; santasList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BroadcastChannel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;santasList&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hello-world&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; messageBox &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hello-world-message&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  messageBox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;button id=&quot;hello-world&quot;&gt;Post Message&lt;/button&gt;
&lt;div id=&quot;hello-world-message&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const santasList = new BroadcastChannel(&quot;santasList&quot;);

document.getElementById(&#39;hello-world&#39;).addEventListener(&#39;click&#39;, () =&gt; {
  santasList.postMessage(&quot;Hello World&quot;);
});

santasList.addEventListener(&#39;message&#39;, ({ data }) =&gt; {
  const messageBox = document.getElementById(&#39;hello-world-message&#39;);
  
  messageBox.textContent = data;
});
    &lt;/script&gt;
    

    

    
    &lt;p&gt;A couple of things to note:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The message will only be output in the non-broadcasting tab (or window)&lt;/li&gt;&lt;li&gt;The message will only sync to currently open contexts, so it will not appear if you open an additional tab (or window)&lt;/li&gt;&lt;li&gt;The broadcast channel is for real-time messaging and will not persist any data&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;demo-app-santas-list&quot;&gt;Demo App: Santa&#39;s List&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/broadcastchannel-api/#demo-app-santas-list&quot; aria-labelledby=&quot;demo-app-santas-list&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For our example, a list of names is presented with options for a &amp;quot;Nice&amp;quot; or &amp;quot;Naughty&amp;quot; behavior. To enable Santa and the elves to check the list twice, we must keep the behavior state in sync across browsing contexts.&lt;/p&gt;&lt;p&gt;In other words, if Priscilla&amp;#39;s behavior is updated from &amp;quot;Nice&amp;quot; to &amp;quot;Naughty,&amp;quot; we want that immediately reflected in any other open tabs to prevent duplicate updates and stale data.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dUhZbqstJ98wyI_santas-list.png?auto=format,compress&quot; alt=&quot;Preview of the Santa&amp;#39;s List app showing the first two names where Priscilla Lloyd is marked &amp;quot;Naughty&amp;quot; and Reece Zavala is marked &amp;quot;Nice&amp;quot;&quot; /&gt;&lt;/p&gt;&lt;p&gt;The demo uses all the same methods we&amp;#39;ve reviewed. However, the logic is extended to update the button state instead of outputting the message.&lt;/p&gt;&lt;p&gt;This app—even as simple as it is—shows just how flexible the API is since you can send data in any shape, and it&amp;#39;s entirely up to your application what you do with that data.&lt;/p&gt;&lt;p&gt;You&amp;#39;ll see a little extra fluff in the CodePen because I chose to create a web component for managing each list item to isolate sending and receiving messages per item.&lt;/p&gt;&lt;p&gt;The basic logic is that once either behavior is selected for a list item, its &lt;code&gt;aria-pressed&lt;/code&gt; state is toggled. The alternate button is also toggled to the opposite state since the behaviors are mutually exclusive binary choices.&lt;/p&gt;&lt;p&gt;Coupled with the &lt;code&gt;name&lt;/code&gt; data and the  &lt;code&gt;id&lt;/code&gt; (&amp;#39;nice&amp;#39; or &amp;#39;naughty&amp;#39;) of the pressed button, the following message is broadcast.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  pressed &lt;span class=&quot;token comment&quot;&gt;// updated aria-pressed state&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A custom event is used to pass the data from the &lt;code&gt;message&lt;/code&gt; event listener. This enables a single &lt;code&gt;message&lt;/code&gt; event listener rather than instantiating one per custom element. In the future, we might have additional actions we want to take upon a received message.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;updateListEvent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;detail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dispatchEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;update-list&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; detail &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;santasList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pressed &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;updateListEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pressed &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The list item listens for the custom event and checks if its &lt;code&gt;name&lt;/code&gt; data matches, and if so, hands off the data to update the corresponding button state for itself.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;update-list&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; detail &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;detail&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// `handleListUpdate` updates button state from &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// both in-page button presses and broadcasts&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;handleListUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;detail&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; detail&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pressed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#39;s the CodePen putting it together. Again, to see it in action, duplicate this tab to see the state reflected in both.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;raBmwbQ&quot; data-user=&quot;5t3ph&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/5t3ph/pen/raBmwbQ&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;Note that since there&amp;#39;s no actual data service behind this simple example, and remembering that the BroadcastChannel in and of itself does not persist data, changes made before opening a new tab will not be reflected. This means that, ultimately, you are likely to need some sort of database or storage solution if data changes need to be saved.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;other-opportunities-for-use&quot;&gt;Other Opportunities for Use&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/broadcastchannel-api/#other-opportunities-for-use&quot; aria-labelledby=&quot;other-opportunities-for-use&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Here are a few ways to use the BroadcastChannel API.&lt;/p&gt;&lt;p&gt;Syncing of all kinds of states, including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;logged in status&lt;/li&gt;&lt;li&gt;notifications (read, unread, new)&lt;/li&gt;&lt;li&gt;file or progress saving&lt;/li&gt;&lt;li&gt;form and uploaded data&lt;/li&gt;&lt;li&gt;chat messages&lt;/li&gt;&lt;li&gt;profile details&lt;/li&gt;&lt;li&gt;store cart changes&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You can also use it to take more advanced and involved actions. I became familiar with the API by using it for my custom conference presentation framework (&lt;a href=&quot;https://www.youtube.com/live/Y50iqMlrqU8?si=xJARjWDrUMEIH_wZ&amp;amp;t=108&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;example presentation&lt;/a&gt;). I used it to navigate slides from a &amp;quot;notes&amp;quot; view via key presses. I also used messages to trigger custom events to mimic element states like hover and focus, reflect typed text updates, and resize code vs. result panels.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/broadcastchannel-api/#resources&quot; aria-labelledby=&quot;resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Check out the following to learn more about the BroadcastChannel API.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Broadcast Channel API&lt;/a&gt; overview on MDN&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/broadcastchannel/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Overview from the Chrome blog&lt;/a&gt;, which also reviews differences from other available messaging APIs&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.telerik.com/blogs/ultimate-guide-broadcast-channel-api&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Tutorial with additional examples for use&lt;/a&gt; from Christian Nwamba&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://thinkdobecreate.com/&quot;&gt;Stephanie Eckles&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z2dU5JbqstJ98wyN_Steph_Eckles.jpeg?auto=format,compress&amp;rect=0,0,1080,1080&amp;w=150&amp;h=150&quot; alt=&quot;Stephanie Eckles&quot; /&gt;
  &lt;p&gt;Stephanie Eckles is a Senior Design Engineer for Adobe Spectrum CSS. She&amp;#39;s also the author of ModernCSS.dev which provides modern solutions to old CSS problems as in-depth articles. Steph has 15+ years of webdev experience that she enjoys sharing as an author, workshop instructor, and conference speaker. She&amp;#39;s an advocate for accessibility, scalable CSS, and web standards. Offline, she&amp;#39;s mom to two girls and a cowboy corgi and enjoys baking.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Stephanie selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS light-dark()</title>
    <link href="https://12daysofweb.dev/2024/css-light-dark/"/>
    <updated>2024-12-21T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/css-light-dark/</id>
    <content type="html">



&lt;p&gt;&lt;code&gt;light-dark()&lt;/code&gt; makes it easy to build websites that respect the user&amp;#39;s preferred color scheme while also providing the ability to override the color scheme without code duplication. Be sure to check out the demo at the bottom! &lt;/p&gt;&lt;p&gt;Before we dive into &lt;code&gt;light-dark()&lt;/code&gt;, let&amp;#39;s take a quick detour to understand &lt;code&gt;color-scheme&lt;/code&gt;. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;color-scheme&quot;&gt;Color scheme &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#color-scheme&quot; aria-labelledby=&quot;color-scheme&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Browsers have a built-in &amp;quot;color scheme&amp;quot; mechanism, which can be specified using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name#color-scheme&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;color-scheme&lt;/code&gt; CSS property&lt;/a&gt; or the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name#color-scheme&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;corresponding meta tag&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;The &lt;code&gt;color-scheme&lt;/code&gt; can be set to either &amp;quot;light&amp;quot; or &amp;quot;dark&amp;quot; to indicate which mode the page supports. It can also be set to a space-separated &amp;quot;light dark&amp;quot; value, which indicates that the page supports both modes. &lt;/p&gt;&lt;p&gt;Typically, you would set this on the &lt;code&gt;html&lt;/code&gt; element so that it gets inherited by everything on the page.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is kinda like saying, &amp;quot;Hey browser, this page supports both light and dark modes, so go look at the user&amp;#39;s preferences and decide which mode to actually use.&amp;quot; &lt;/p&gt;&lt;p&gt;The browser then uses the resolved color scheme value to determine the default colors for things like the page background, text color, scrollbars, &lt;a href=&quot;https://blogs.windows.com/msedgedev/2021/06/16/dark-mode-html-form-controls/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;form controls&lt;/a&gt;, and &lt;a href=&quot;https://drafts.csswg.org/css-color-4/#css-system-colors&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;system colors&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;It&amp;#39;s worth clarifying at this point that &lt;code&gt;color-scheme&lt;/code&gt; is a completely separate concept from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt; media query&lt;/a&gt;, which you might have used in the past to implement a dark mode. The media query is only concerned with looking at the user preferences. Even if you&amp;#39;re using the &lt;em&gt;media query&lt;/em&gt;, it should be paired with the &lt;code&gt;color-scheme&lt;/code&gt; &lt;em&gt;property &lt;/em&gt;so that scrollbars and form controls get more appropriate default styles. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Everything we&amp;#39;ve learned about &lt;code&gt;color-scheme&lt;/code&gt; thus far has been &lt;a href=&quot;https://caniuse.com/?search=color-scheme&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;widely available&lt;/a&gt; across browsers for many years now. &lt;/p&gt;&lt;p&gt;Now that we understand &lt;code&gt;color-scheme&lt;/code&gt;, we can look at the new &lt;code&gt;light dark()&lt;/code&gt; feature! &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;enter-light-dark&quot;&gt;Enter light-dark() &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#enter-light-dark&quot; aria-labelledby=&quot;enter-light-dark&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You might have noticed that, up until now, &lt;code&gt;color-scheme&lt;/code&gt; is somewhat of a one-way signal. Browsers can use &lt;code&gt;color-scheme&lt;/code&gt; to adjust the default colors (and system colors), but authors cannot use it in their own code to adjust their custom styles. &lt;/p&gt;&lt;p&gt;This is where &lt;code&gt;light-dark()&lt;/code&gt; comes in. From the &lt;a href=&quot;https://www.w3.org/TR/css-color-5/#light-dark&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;spec&lt;/a&gt;: &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;System colors have the ability to react to the current used color scheme value. The &lt;code&gt;light-dark()&lt;/code&gt; function exposes the same capability to authors. &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;code&gt;light-dark()&lt;/code&gt; is a CSS function that accepts two color values and returns one of them based on the &lt;a href=&quot;https://drafts.csswg.org/css-color-adjust/#used-color-scheme&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;used &lt;code&gt;color-scheme&lt;/code&gt;&lt;/a&gt;. The following snippet will make all links be &lt;code&gt;DeepPink&lt;/code&gt; in light mode and &lt;code&gt;HotPink&lt;/code&gt; in dark mode.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:any-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DeepPink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HotPink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;#39;s a clean and concise way of doing something that would have required multiple CSS rules and media queries in the past. &lt;/p&gt;&lt;p&gt;The two colors don&amp;#39;t need to be hardcoded; they can reference custom properties (aka &amp;quot;CSS variables&amp;quot;). And they can also be referenced by&lt;code&gt; &lt;/code&gt;other custom properties (as we&amp;#39;ll see later). &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:any-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--accent-light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--accent-dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;light-dark()&lt;/code&gt; has been &lt;a href=&quot;https://caniuse.com/mdn-css_types_color_light-dark&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;newly available&lt;/a&gt; across modern browsers since early 2024. For older browsers, we can transpile our code using &lt;a href=&quot;https://lightningcss.dev/transpilation.html#light-dark()-color-function&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;LightningCSS&lt;/a&gt; or a &lt;a href=&quot;https://www.npmjs.com/package/@csstools/postcss-light-dark-function&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;PostCSS plugin&lt;/a&gt;. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;themed-variables-using-light-dark&quot;&gt;Themed variables using light-dark() &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#themed-variables-using-light-dark&quot; aria-labelledby=&quot;themed-variables-using-light-dark&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To get the most out of &lt;code&gt;light-dark()&lt;/code&gt;, it is best used globally for the purpose of setting up themed custom properties. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s start by defining three custom properties: &lt;code&gt;--accent&lt;/code&gt;, &lt;code&gt;--bg&lt;/code&gt;, and &lt;code&gt;--fg&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DeepPink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HotPink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;White&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Black&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Don&amp;#39;t pay mind to the actual values in this example. It&amp;#39;s probably not desirable to use the built-in named CSS colors. Usually, you&amp;#39;ll want to agonize over picking the right colors. I&amp;#39;ll leave that as an exercise for the reader. (If you need a little push, &lt;a href=&quot;https://open-props.style/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Open Props&lt;/a&gt; provides a few different color scales which can be a good starting point for your color system.) &lt;/p&gt;&lt;p&gt;Once the custom properties are set up, we can use them everywhere in our CSS. Notice how we don&amp;#39;t need to repeat the raw color values. Because these custom properties were set up using &lt;code&gt;light-dark()&lt;/code&gt;, the whole page automatically works in both light and dark modes without needing to adjust anything at the component level. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;accent-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--accent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;*:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--accent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;:any-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.surface&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* and so on... */&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;overriding-color-scheme&quot;&gt;Overriding color-scheme &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#overriding-color-scheme&quot; aria-labelledby=&quot;overriding-color-scheme&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;So far, we&amp;#39;ve only seen how &lt;code&gt;light-dark()&lt;/code&gt; can replace a media query. This is great, but we usually want more: the site should respect the user&amp;#39;s preference by default, but the user should also be able to override the default color scheme. &lt;/p&gt;&lt;p&gt;The key insight here is that &lt;code&gt;light-dark()&lt;/code&gt; is tied to the &lt;code&gt;color-scheme&lt;/code&gt;, rather than to user preference. While setting &lt;code&gt;color-scheme: light dark&lt;/code&gt; will match the user preference, we can also override it manually. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s say our website has a theme toggle, which sets a &lt;code&gt;data-color-scheme&lt;/code&gt; attribute on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/*&lt;br /&gt; * Call this function from your theme toggle.&lt;br /&gt; * @example&lt;br /&gt; * setColorScheme(&quot;light&quot;);&lt;br /&gt; * setColorScheme(&quot;dark&quot;);&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setColorScheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, we can use this data attribute as a CSS selector to change our &lt;code&gt;color-scheme&lt;/code&gt;. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;[data-color-scheme=&quot;light&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;[data-color-scheme=&quot;dark&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Changing the &lt;code&gt;color-scheme&lt;/code&gt; will automatically result in all instances of &lt;code&gt;light-dark()&lt;/code&gt; returning the appropriate color value. In this instance, we are setting &lt;code&gt;color-scheme&lt;/code&gt; on the same element (&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;) where our custom properties are defined. However, &lt;code&gt;light-dark()&lt;/code&gt; also works for descendant elements because &lt;code&gt;color-scheme&lt;/code&gt; is an inherited property. &lt;/p&gt;&lt;p&gt;That&amp;#39;s really all the code we need to implement light and dark modes. It respects the user preference (without a media query!) and can also be overridden. &lt;/p&gt;&lt;p&gt;For comparison, implementing the same functionality without &lt;code&gt;light-dark()&lt;/code&gt; would look something like the following. We would need to define the custom properties &lt;em&gt;four &lt;/em&gt;different times, two of which are entirely duplicate copies of each other. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* without light-dark() */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; DeepPink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; HotPink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;[data-color-scheme=&quot;light&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; DeepPink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;[data-color-scheme=&quot;dark&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; HotPink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Meanwhile, with &lt;code&gt;light-dark()&lt;/code&gt;, we can keep all our custom properties neatly defined in a single place. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* with light-dark() */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--accent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DeepPink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HotPink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;White&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Black&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Black&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; White&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The future is bright (and dark)! &lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;&lt;em&gt;A brief note about accessibility&lt;/em&gt;: When implementing a color system, be sure to pick color pairings that meet &lt;a href=&quot;https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;color contrast requirements&lt;/a&gt;. Checking contrast scores at the theme level is the most effective way to build an accessible color system. You can also create higher-contrast versions of your base color themes by combining &lt;code&gt;light-dark()&lt;/code&gt; with a custom selector or the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;prefers-contrast&lt;/code&gt; media query&lt;/a&gt; (or both). &lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;to-the-codepen&quot;&gt;To the CodePen! &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#to-the-codepen&quot; aria-labelledby=&quot;to-the-codepen&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s take everything we&amp;#39;ve learned about &lt;code&gt;light-dark()&lt;/code&gt; and put it to use. &lt;/p&gt;&lt;p&gt;This demo shows a tri-state toggle that works only by changing the document&amp;#39;s &lt;code&gt;color-scheme&lt;/code&gt;. All of the theme-related CSS is wrapped under &lt;code&gt;@layer theme&lt;/code&gt;. &lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ogvbMQa&quot; data-user=&quot;hi_mayank&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/hi_mayank/pen/ogvbMQa&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;further-reading&quot;&gt;Further reading &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-light-dark/#further-reading&quot; aria-labelledby=&quot;further-reading&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you&amp;#39;re anything like me, you learn new topics by absorbing the same information from several different sources. So here are a few good links related to &lt;code&gt;color-schem&lt;/code&gt;e and &lt;code&gt;light-dark()&lt;/code&gt;: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2023/10/09/the-future-of-css-easy-light-dark-mode-color-switching-with-light-dark/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Easy Light-Dark Mode Color Switching with light-dark()&lt;/a&gt; by Bramus&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/come-to-the-light-dark-side/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Come To The Light-dark()&lt;/a&gt; Side by Sara Joy &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://weblog.anniegreens.lol/2024/04/what-ive-learned-about-css-color-scheme-and-system-color&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;What I&amp;#39;ve learned about CSS color-scheme and friends&lt;/a&gt; by Anne Sturdivant&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-color-adjust-1/#color-scheme-prop&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;Opting Into a Preferred Color Scheme: the color-scheme property&lt;/a&gt; from CSSWG (this is a fun read!) &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/the-perfect-theme-switch/&quot; target=&quot;_self&quot; rel=&quot;noopener noreferrer&quot;&gt;The Perfect Theme Switch Component&lt;/a&gt; by Aleksandr Hovhannisyan&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://mayank.co/&quot;&gt;Mayank&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/a6be90f2-9d0e-44fd-a6da-d50e2a0dbea5_mayank.jpeg?auto=format,compress&amp;rect=0,0,460,460&amp;w=150&amp;h=150&quot; alt=&quot;Mayank&quot; /&gt;
  &lt;p&gt;Mayank is a design engineer who cares deeply about accessibility and inclusivity. They enjoy working with new, revolutionary web tech, such as HTML and CSS. In their free time, they run their mouth on their personal blog.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Mayank selected &lt;strong&gt;&lt;a href=&quot;https://www.forthegworls.com/home&quot;&gt;For the Gworls&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.forthegworls.com/home&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.squarespace-cdn.com/content/v1/5ee6c85186e6643447dc54fc/38ebbdaa-0f23-48d7-8c59-1debf6d0880e/Pink_Green+Transparent+copy.png?format=1500w&quot; alt=&quot;For the Gworls&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;For The Gworls is a Black trans-led collective that raises funds to directly help Black trans people pay for rent assistance, gender-affirming surgeries, and critical medical expenses.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>JS Import Maps</title>
    <link href="https://12daysofweb.dev/2024/js-import-maps/"/>
    <updated>2024-12-20T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/js-import-maps/</id>
    <content type="html">



&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#introduction&quot; aria-labelledby=&quot;introduction&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Just as holiday shopping requires careful planning and organization, managing JavaScript dependencies in web applications demands thoughtful coordination. Traditionally, web developers have relied on bundlers like webpack or browserify to handle bare module imports. &lt;/p&gt;&lt;p&gt;But what if we could easily manage our dependencies? Enter Import Maps, a native browser specification that lets you control JavaScript module loading without the need for bundling tools.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;understanding-import-maps&quot;&gt;Understanding Import Maps&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#understanding-import-maps&quot; aria-labelledby=&quot;understanding-import-maps&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-problem-with-bare-imports&quot;&gt;The Problem with Bare Imports&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#the-problem-with-bare-imports&quot; aria-labelledby=&quot;the-problem-with-bare-imports&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we write modern JavaScript, we often use bare import statements like:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Snowflake &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;winter-animations&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Without build tools, browsers can&amp;#39;t resolve these bare module specifiers - they need complete URLs. It&amp;#39;s like trying to deliver presents without knowing the full address!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;how-import-maps-help&quot;&gt;How Import Maps Help&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#how-import-maps-help&quot; aria-labelledby=&quot;how-import-maps-help&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Import Maps tell browsers exactly where to find these modules, mapping bare import names to their actual locations. Think of them as your holiday shipping manifest—a clear guide showing where each package needs to go.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;example-usage&quot;&gt;Example Usage&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#example-usage&quot; aria-labelledby=&quot;example-usage&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s create an example using Import Maps to build a winter-themed countdown timer.&lt;/p&gt;&lt;p&gt;First, create your &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Define our Import Map --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;importmap&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;date-fns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/date-fns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;snowfall-effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/snowfall-effect&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./winter.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;countdown&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then create a file called &lt;code&gt;winter.js&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; differenceInDays &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;date-fns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createSnowfall &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;snowfall-effect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create countdown to winter solstice&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; winterSolstice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2024&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; countdown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;countdown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateCountdown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; daysLeft &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;differenceInDays&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;winterSolstice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    countdown&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;daysLeft&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; days until Winter Solstice!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update daily&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;updateCountdown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updateCountdown&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;86400000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Add some winter magic&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;createSnowfall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;density&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.5&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;advanced-features&quot;&gt;Advanced Features&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#advanced-features&quot; aria-labelledby=&quot;advanced-features&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;scoped-imports&quot;&gt;Scoped Imports&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#scoped-imports&quot; aria-labelledby=&quot;scoped-imports&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Like organizing different gifts for different family members, Import Maps allow you to specify different versions of the same package for different parts of your application.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;animation-lib&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/shared/animation-v2.js&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;scopes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;/legacy/&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;animation-lib&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/shared/animation-v1.js&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;version-management&quot;&gt;Version Management&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#version-management&quot; aria-labelledby=&quot;version-management&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Need to maintain different versions for different features? Import Maps let you handle this elegantly:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;snowfall-effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/modules/snowfall-v2.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;snowfall-effect-legacy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/modules/snowfall-v1.js&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;browser-support-and-fallbacks&quot;&gt;Browser Support and Fallbacks&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#browser-support-and-fallbacks&quot; aria-labelledby=&quot;browser-support-and-fallbacks&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As of late 2024, Import Maps are supported in all modern browsers. However, for broader compatibility, you can use the ES Module Shims polyfill:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://ga.jspm.io/npm:es-module-shims@1.7.0/dist/es-module-shims.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;vs-code-extension&quot;&gt;VS Code Extension&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#vs-code-extension&quot; aria-labelledby=&quot;vs-code-extension&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Alternatively, there is a VS Code extension which can automatically generate and inject import maps for modules and HTML pages. You can learn more about this extension &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=JSPM.jspm-vscode&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;project-ideas&quot;&gt;Project Ideas&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#project-ideas&quot; aria-labelledby=&quot;project-ideas&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Here are some projects you can build over the holidays to help you master Import Maps:&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;1-winter-task-tracker-with-snowfall-effects&quot;&gt;1. Winter Task Tracker with Snowfall Effects&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#1-winter-task-tracker-with-snowfall-effects&quot; aria-labelledby=&quot;1-winter-task-tracker-with-snowfall-effects&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Build a task management system where completed tasks trigger animated snowflakes. Use these libraries.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;tsparticles&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/tsparticles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;sortablejs&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/sortablejs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;date-fns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/date-fns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;@lit/reactive-element&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/@lit/reactive-element&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key Features to Implement:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use &lt;code&gt;tsparticles&lt;/code&gt; for snowflake animations when tasks are completed&lt;/li&gt;&lt;li&gt;Implement drag-and-drop task reordering with &lt;code&gt;sortablejs&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Add due date handling with &lt;code&gt;date-fns&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Create custom task components with &lt;code&gt;@lit/reactive-element&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;2-holiday-gift-list-organizer&quot;&gt;2. Holiday Gift List Organizer&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#2-holiday-gift-list-organizer&quot; aria-labelledby=&quot;2-holiday-gift-list-organizer&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Create a gift tracking application with categories, budgeting, and progress tracking.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;alpine&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/alpinejs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;currency.js&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/currency.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;chart.js&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/chart.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/uuid&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key Features to Implement:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use &lt;code&gt;alpine&lt;/code&gt; for reactive UI components&lt;/li&gt;&lt;li&gt;Handle gift budget calculations with &lt;code&gt;currency.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Create spending visualizations with &lt;code&gt;chart.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Generate unique IDs for gifts using &lt;code&gt;uuid&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;3-winter-weather-dashboard&quot;&gt;3. Winter Weather Dashboard&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#3-winter-weather-dashboard&quot; aria-labelledby=&quot;3-winter-weather-dashboard&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Build a weather dashboard that pulls data from multiple sources and displays it with winter-themed visualizations.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;d3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/d3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;axios&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/axios&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;dayjs&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/dayjs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;weather-icons&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://cdn.skypack.dev/weather-icons&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;scopes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;/weather/&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;temp-conversion&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./utils/temperature.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;weather-api&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./services/weather-service.js&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key Features to Implement:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create weather visualizations with &lt;code&gt;d3&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Handle API requests with &lt;code&gt;axios&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Manage dates and times with &lt;code&gt;dayjs&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Display weather conditions using &lt;code&gt;weather-icons&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Import Maps Specification: &lt;a href=&quot;https://github.com/WICG/import-maps&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/WICG/import-maps&lt;/a&gt;&lt;/li&gt;&lt;li&gt;MDN Documentation: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap&lt;/a&gt;&lt;/li&gt;&lt;li&gt;ES Module Shims: &lt;a href=&quot;https://github.com/guybedford/es-module-shims&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/guybedford/es-module-shims&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/js-import-maps/#conclusion&quot; aria-labelledby=&quot;conclusion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Import Maps provide a powerful way to manage JavaScript dependencies directly in the browser. By eliminating the need for bundlers in many cases, they simplify development workflows and provide more direct control over module loading.&lt;/p&gt;&lt;p&gt;Thanks for reading. I hope this article has been helpful in getting you started with import maps. Happy holidays! Cheers!&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://lo-victoria.com/&quot;&gt;Victoria Lo&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z18cdZbqstJ98hJz_victoria-lo.png?auto=format,compress&amp;rect=0,0,500,500&amp;w=150&amp;h=150&quot; alt=&quot;Victoria Lo&quot; /&gt;
  &lt;p&gt;I&amp;#39;m a technical blogger, web developer and solutions engineer. You can find my blog at: https://lo-victoria.com/&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Victoria selected &lt;strong&gt;&lt;a href=&quot;https://girlswhocode.com/&quot;&gt;Girls Who Code&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://girlswhocode.com/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/Z18cOpbqstJ98hJv_logo-girls-who-code.png?auto=format,compress&quot; alt=&quot;Girls Who Code&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Girls Who Code is an organization working to close the gender gap in technology by inspiring, educating, and equipping young women with the computing skills needed to pursue modern opportunities. They offer coding clubs, summer programs, and college/career prep.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS box-decoration-break</title>
    <link href="https://12daysofweb.dev/2024/css-box-decoration-break/"/>
    <updated>2024-12-19T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/css-box-decoration-break/</id>
    <content type="html">



&lt;p&gt;&lt;code&gt;box-decoration-break&lt;/code&gt; is a CSS property that lets you decide what the decorations of a box should do if that box is broken across multiple lines.&lt;/p&gt;&lt;p&gt;Now that sentence probably means nothing if you don&amp;#39;t already know what &lt;code&gt;box-decoration-break&lt;/code&gt; does, so let&amp;#39;s back up a whole bunch of steps and figure out why this is something that needs to be decided on.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-is-a-box&quot;&gt;What is a box?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#what-is-a-box&quot; aria-labelledby=&quot;what-is-a-box&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s start with the first part: boxes. In CSS, everything is a box. Every element in your DOM is a box, every pseudo-element you add in CSS is a box, and even every text node is a box.&lt;/p&gt;&lt;p&gt;In other words, the entire web page is made up of rectangles. There are different types of rectangles, but for &lt;code&gt;box decoration-break&lt;/code&gt;, there are two types we need to know about: block boxes and inline boxes. In CSS, elements can either be &amp;quot;block&amp;quot; or &amp;quot;inline.&amp;quot;&lt;/p&gt;


  
    

    

    
    &lt;style&gt;
    .block-el {
  text-align: center;
  aspect-ratio: 1/1;
  max-block-size: 200px;
  display: grid;
  place-items: center;
  border: 4px solid dodgerblue;
  padding: 40px
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Example of a block element&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.block-el&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1/1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px solid dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40px&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;block-el&quot;&gt;This is a block box&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;When an element is a block element, it takes up the entire width of the parent element, and if you add a new block element after it, that will be placed below the first block element. Things like divs, headings, and paragraphs are block elements: They stack on top of each other.&lt;/p&gt;&lt;p&gt;Inline elements, on the other hand, only take up the space they need and sit &amp;quot;inline&amp;quot; with the surrounding text. Examples include spans, links, and strong elements.&lt;/p&gt;
    

    
    &lt;style&gt;
    .inline-el {
  line-height: 2.5;
  text-align: center;
}

.inline-el span {
  border: 4px solid dodgerblue;
  padding: 4px 10px
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Example of an inline elememt&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.inline-el&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2.5&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.inline-el span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px solid dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 10px&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;inline-el&quot;&gt;
   Hello, &lt;span&gt;this is a long unbroken inline box&lt;/span&gt; in a text line.
&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-are-decorations&quot;&gt;What are decorations?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#what-are-decorations&quot; aria-labelledby=&quot;what-are-decorations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In CSS, (box-)decorations are things like borders, outlines, backgrounds, and shadows (but also margin, padding, and clip-path). They let you change the box from a transparent rectangle into a nicely glowing pill button, a floating card, or a recessed input field.&lt;/p&gt;&lt;p&gt;Usually, these decorations are applied to all sides of the box: top, right, bottom, and left, though you can also apply borders and outlines only to specific sides.&lt;/p&gt;
    

    
    &lt;style&gt;
    .decorated {
  font-size: 1.5rem;
  font-weight: bold;
  color: white;
  outline: 5px dashed red;
  border: 5px dashed green;
  padding: 20px;
  aspect-ratio: initial;
  background: repeating-linear-gradient(45deg,  red,  red 10px,  green 10px,  green 20px);
  border-radius: 999px;
  box-shadow: 0 0 20px yellow, 0 0 10px 5px inset yellow;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Simple decorated box&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.decorated&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px dashed red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px dashed green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeating-linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;45deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  red&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  red 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  green 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  green 20px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 999px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 20px yellow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0 0 10px 5px inset yellow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;decorated&quot;&gt;This is a decorated box&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;whats-a-break&quot;&gt;What’s a break?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#whats-a-break&quot; aria-labelledby=&quot;whats-a-break&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Most inline elements are short and fit start-to-end in a single line. If an inline element is very long, it will automatically wrap across multiple lines.&lt;/p&gt;&lt;p&gt;To do that, the browser first renders the inline element as a very wide rectangle that includes all the contents in a single line. Then, it will break that rectangle up into however many lines it needs to make the content fit the screen.&lt;/p&gt;&lt;p&gt;This breaking is where things might not happen as you expect. Let’s say you have an inline box with a blue border on all sides: top, right, bottom, and left. Those borders are exactly where you think they are when the browser first renders that very long inline element.&lt;/p&gt;
    

    
    &lt;style&gt;
    .initial-box {
  border:4px solid dodgerblue;
  padding: 4px 10px;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Initial box styles&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.initial-box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4px solid dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;initial-box&quot;&gt;
   &lt;span&gt;This is a long unbroken inline box&lt;/span&gt;
&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;But then the browser chops it up into multiple segments, and while the element still has the border at the left and right sides, there’s now a bunch of &lt;strong&gt;new&lt;/strong&gt; left and right sides to this element, and they look awful&lt;code&gt;.&lt;/code&gt;&lt;/p&gt;
    

    
    &lt;style&gt;
    .broken-box {
 width: 100px;
}

.broken-box span {
  border:4px solid dodgerblue;
  padding: 4px 10px;
}

    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Broken appearance box styles&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.broken-box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.broken-box span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4px solid dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;broken-box&quot;&gt;
   &lt;span&gt;This is a long unbroken inline box&lt;/span&gt;
&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;enter-box-decoration-break&quot;&gt;Enter box-decoration-break&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#enter-box-decoration-break&quot; aria-labelledby=&quot;enter-box-decoration-break&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With &lt;code&gt;box-decoration-break&lt;/code&gt;, we can tell the browser how to handle those breaks in one of two ways:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Slice&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;This is the default value, and it’s like the example above. The browser renders the inline element in one long line and then chops that line up into multiple segments, leading to “frayed” edges on either side for everything but the first and last lines.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Clone&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Setting &lt;code&gt;box-decoration-break&lt;/code&gt; to &lt;code&gt;clone&lt;/code&gt; will take those decorations and clone them to each segment, meaning that each line is turned into its own little box.&lt;/p&gt;
    

    
    &lt;style&gt;
    .box-decoration-break-clone {
 width: 100px;
}

.box-decoration-break-clone span {
  border:4px solid dodgerblue;
  padding: 4px 10px;
  
  box-decoration-break: clone;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Using box-decoration-break: clone&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.box-decoration-break-clone&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.box-decoration-break-clone span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4px solid dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;box-decoration-break-clone&quot;&gt;
  &lt;span&gt;This is a long broken inline box&lt;/span&gt;
&lt;/p&gt;

    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;Not only does this cause the borders you might have expected to appear again, also see how the padding on the left and right sides are now also applied to each line, rather than only to the beginning and end. &lt;/p&gt;&lt;p&gt;A practical application of this is when you want to create a marker-like effect on some text to make it seem like you have highlighted a couple of lines.&lt;/p&gt;&lt;p&gt;Here’s that effect without cloned box-decoration-break.&lt;/p&gt;
    

    
    &lt;style&gt;
    .marker-1 {
  width: 250px;
  line-height: 1.5;
  font-size: 1.75rem;
}

.marker-1 span {
  padding-inline: 20px;
  background: linear-gradient(105deg, transparent 10px, cyan 10px, cyan calc(100% - 10px), transparent calc(100% - 10px));
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Marker effect - no box-decoration-break&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.marker-1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 250px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.marker-1 span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;105deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cyan 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cyan &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;marker-1&quot;&gt;
  &lt;span&gt;This is a long broken inline box&lt;/span&gt;
&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;And here it is with cloned &lt;code&gt;box-decoration-break&lt;/code&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    .marker-2 {
  width: 250px;
  line-height: 1.5;
  font-size: 1.75rem;
}

.marker-2 span {
  padding-inline: 20px;
  background: linear-gradient(105deg, transparent 10px, cyan 10px, cyan calc(100% - 10px), transparent calc(100% - 10px));

  box-decoration-break: clone;
}

    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Marker effect - with box-decoration-break&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.marker-2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 250px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.marker-2 span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;105deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cyan 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cyan &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;marker-2&quot;&gt;
  &lt;span&gt;This is a long broken inline box&lt;/span&gt;
&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-re-introduction&quot;&gt;The re-introduction&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#the-re-introduction&quot; aria-labelledby=&quot;the-re-introduction&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As I said at the start of this article, you might have already used this feature! It’s been available in Firefox since 2014, Chromium-based browsers since 2013, and Safari since 2013. &lt;/p&gt;&lt;p&gt;The Chromium and Safari implementations, however, had the &lt;code&gt;-webkit-&lt;/code&gt; prefix because they only had partial support. It only supported the &lt;code&gt;box-decoration-break&lt;/code&gt; of inline boxes. Inline boxes are where you encounter this issue most frequently so there is a high chance that you’ve already used this at some point in the last decade. &lt;/p&gt;&lt;p&gt;But there are cases where block boxes can also get broken apart: in (infrequently used) multi-column layout. Chrome implemented support for that earlier this year and thus removed the prefix, while Safari has no support for that yet and still has the prefix. &lt;/p&gt;&lt;p&gt;To support both browsers, always first write the prefixed version:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;-webkit-box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We do this because in CSS, the last declaration wins. When that last declaration is the unprefixed one, as soon as Safari also adds support, it will default to using the proper, full implementation. Until that time, Safari doesn’t understand &lt;code&gt;box-decoration-break&lt;/code&gt; and will ignore it, using only the prefixed version.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;block-level-box-decoration-break-for-multi-column-layout&quot;&gt;Block-level box-decoration-break for multi-column layout.&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#block-level-box-decoration-break-for-multi-column-layout&quot; aria-labelledby=&quot;block-level-box-decoration-break-for-multi-column-layout&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In the same way that inline boxes can get split up across multiple horizontal lines if they don’t fit horizontally, block boxes can get split up across multiple columns if they don’t fit in a single column vertically, like the following demo adapted from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/box-decoration-break#block_box_fragments&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN&lt;/a&gt;:&lt;/p&gt;
    

    
    &lt;style&gt;
    /* our block style */
.multi-col span {
  display: block;
  font-size:1.5rem;
  font-weight:bold;
  color: white;
  outline: 5px dashed red;
  border: 5px dashed green;
  padding: 20px;
  aspect-ratio: initial;
  background: repeating-linear-gradient(45deg,  red,  red 10px,  green 10px,  green 20px);
  border-radius: 999px;
  box-shadow: 0 0 20px yellow, 0 0 10px 5px inset yellow;
}

.base {
  width: 33%;
}

.columns {
  columns: 3;
}

.default {
  box-decoration-break: slice;
}

.clone {
  box-decoration-break: clone;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Multi-column and box-decoration-break&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* our block style */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.multi-col span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px dashed red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px dashed green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeating-linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;45deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  red&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  red 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  green 10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  green 20px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 999px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 20px yellow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0 0 10px 5px inset yellow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.base&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 33%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.columns&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slice&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.clone&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-decoration-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;multi-col&quot;&gt;

&lt;div class=&quot;base&quot;&gt;
  &lt;span&gt;The quick orange fox&lt;/span&gt;
&lt;/div&gt;
&lt;br /&gt;

&lt;h2&gt;&#39;box-decoration-break: slice&#39;&lt;/h2&gt;
&lt;div class=&quot;columns&quot;&gt;
  &lt;span class=&quot;default&quot;&gt;The quick orange fox&lt;/span&gt;
&lt;/div&gt;

&lt;h2&gt;&#39;box-decoration-break: clone&#39;&lt;/h2&gt;
&lt;div class=&quot;columns&quot;&gt;
  &lt;span class=&quot;clone&quot;&gt;The quick orange fox&lt;/span&gt;
&lt;/div&gt;

&lt;/div&gt;

    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;thats-box-decoration-break&quot;&gt;That’s box-decoration-break&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-box-decoration-break/#thats-box-decoration-break&quot; aria-labelledby=&quot;thats-box-decoration-break&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When an element is broken across multiple lines (or columns), &lt;code&gt;box-decoration-break&lt;/code&gt; enables you to decide whether each segment should clone the decorations for themselves or if the box should remain sliced.&lt;/p&gt;&lt;p&gt;It’s fully available in Chromium-based browsers and Firefox. In Safari you can use it for inline boxes with the &lt;code&gt;-webkit-&lt;/code&gt; prefix. If you want to learn more, here are some additional resources:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/box-decoration-break&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;box-decoration-break on MDN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/box-decoration-break&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The box-decoration-break property in Chrome 130 on web.dev&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://kilianvalkhof.com/&quot;&gt;Kilian Valkhof&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/e01991d2-1826-48b5-90e5-8429a0b0c191_kilian.jpg?auto=format,compress&amp;rect=0,0,512,512&amp;w=150&amp;h=150&quot; alt=&quot;Kilian Valkhof&quot; /&gt;
  &lt;p&gt;Kilian is a web developer from the netherlands, building Polypane.app, the browser for developers.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Kilian selected &lt;strong&gt;&lt;a href=&quot;https://www.givingwhatwecan.org/&quot;&gt;Giving Green Fund&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.givingwhatwecan.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://cdn.sanity.io/images/4rsg7ofo/production/eb68062c2664d44072541adadb3aa1ff52f0003b-500x500.png?w=3840&amp;q=75&amp;fit=clip&amp;auto=format&quot; alt=&quot;Giving Green Fund&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The climate crisis sits at the heart of many problems around the world, increasing inequality and disproportionately affecting those least responsible for it. If we want to keep earth livable for our children, we need to fight it at many fronts. Giving Green is a fund that research projects and funds those most effective.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Declarative Shadow DOM</title>
    <link href="https://12daysofweb.dev/2024/declarative-shadow-dom/"/>
    <updated>2024-12-18T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/declarative-shadow-dom/</id>
    <content type="html">



&lt;p&gt;What we are able to build using the web platform has gone into overdrive, especially in the last two years. Most of the action has been in the areas of CSS and JavaScript, but there have also been some important additions to HTML.&lt;/p&gt;&lt;p&gt;However, one piece of the puzzle has proven to be elusive: the ability to build reusable and isolated components.&lt;/p&gt;&lt;p&gt;But wait, what about web components? I hear you ask, and you would be correct. With the HTML template element, custom elements, and the shadow DOM finally getting widespread adoption in user agents, we can build components that satisfy most of our needs.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-problem&quot; aria-labelledby=&quot;the-problem&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Leaving the complaints about the general developer experience when writing web components aside for the moment, there is one rather striking challenge that still has most web developers reaching for a framework: server-side rendering and/or static site generation.&lt;/p&gt;&lt;p&gt;There are multiple reasons we may want to take advantage of server-side rendering. Some of these are related to performance and accessibility, but also to search engine optimization, which is still an important topic in 2024, even though Perplexity and friends might want us to believe differently.&lt;/p&gt;&lt;p&gt;I would much prefer to know that users can access a page&amp;#39;s content even if JavaScript fails to execute for whatever reason. Also, some applications (both desktop and web-based) do not execute JavaScript and instead opt to provide the user with a clean and distraction-free reading environment.&lt;/p&gt;&lt;p&gt;In these instances, web components will let you and your users down.&lt;/p&gt;&lt;p&gt;&lt;em&gt;But…&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The web and the technologies that power it are constantly evolving, and so too have web components. In this article, I will first highlight the challenge that has made using web components, specifically the shadow DOM, a non-starter for many projects. But then, we will explore an evolution of shadow DOM that is already well-supported in modern browsers, known as declarative shadow DOM, and learn how it breaks down one of the final obstacles and enables us to write reusable, isolated web components that can be server-side rendered or used as part of a statically generated website.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I will lean on the Astro framework to demonstrate the problem with shadow DOM and the solution enabled by declarative shadow DOM. However, this will be purely for the &amp;quot;server-side rendering&amp;quot; (or static site generation, depending on how you wish to look at it) capability. The framework or technology also does not have to be JavaScript or Node-based; the same results can be achieved using other frameworks such as Django (Python), Ruby on Rails (Ruby), Laravel (PHP), or Rocket (Rust).&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-problem-with-shadow-dom&quot;&gt;The Problem with Shadow DOM&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-problem-with-shadow-dom&quot; aria-labelledby=&quot;the-problem-with-shadow-dom&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To understand some of the challenges with shadow DOM and why you would want to use It, we will build a simple user card component. We do have a couple of requirements that need to be met when building and using this component.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z142j5bqstJ98gjj_shadow-dom-1.png?auto=format,compress&quot; alt=&quot;Above is an example use case for the card component we will be building.&quot; /&gt;&lt;figcaption&gt;Above is an example use case for the card component we will be building.&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;our-requirements&quot;&gt;Our Requirements&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#our-requirements&quot; aria-labelledby=&quot;our-requirements&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;We want clean, semantic, and accessible HTML.&lt;/li&gt;&lt;li&gt;We want our CSS to be scoped to our card component but, we do not want to have to write our CSS in JavaScript and would prefer to have our component CSS in its own CSS source file.&lt;/li&gt;&lt;li&gt;The data for each card will come from an external API so we need a way to load this data.&lt;/li&gt;&lt;li&gt;We want to be able to access our card components with their data available, even if JavaScript is not available.&lt;/li&gt;&lt;li&gt;We want to be able to use our component during server-side rendering, as part of a statically generated site, or even in more traditional server based frameworks such as those mentioned in the note earlier in this article.&lt;/li&gt;&lt;li&gt;We would very much appreciate a great developer experience that allows for ease of implementation and maintainability.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;That is quite a set of requirements, but they are not uncommon when building software and websites for the web.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-html&quot;&gt;The HTML&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-html&quot; aria-labelledby=&quot;the-html&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let us start by satisfying our first requirement: we want clean, semantic, and accessible HTML.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;nimbus-team-user-card-tmpl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-avatar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-role&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-email&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Email:&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-phone&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Phone:&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-social&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon icon-social-bsky&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;_blank&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;noopener noreferrer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Follow @employee on @platform&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon icon-social-linkedin&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;_blank&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;noopener noreferrer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Follow @employee on @platform&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon icon-social-mastodon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;_blank&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;noopener noreferrer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Follow @employee on @platform&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is a lot of HTML! For the most part, though, you have most likely seen all of it before. The only two items that might be new are the &lt;code&gt;nimbus-team&lt;/code&gt; element and the &lt;code&gt;template&lt;/code&gt; element. The first, &lt;code&gt;nimbus-team&lt;/code&gt; is our custom element that does not really exist yet. The second is the &lt;code&gt;template&lt;/code&gt; element we are using to well house our user card template.&lt;/p&gt;&lt;p&gt;There are some optimizations we can make to this template when we use it within a framework such as Astro, but for the moment, we will focus more on the more “traditional” way you would build this type of web component even when not inside a framework such as Astro. We will take full advantage of it later when we refactor this to use declarative shadow DOM.&lt;/p&gt;&lt;p&gt;If you open the HTML document in your browser right now, you will be presented with a blank page. This is because our custom element has not been defined and registered yet, and the content of a &lt;code&gt;template&lt;/code&gt; element is not visible when viewed in a browser.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-initial-custom-element-javascript&quot;&gt;The initial custom element JavaScript&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-initial-custom-element-javascript&quot; aria-labelledby=&quot;the-initial-custom-element-javascript&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To address the first part, we need to add some JavaScript. In a folder called &lt;code&gt;js&lt;/code&gt;, at the root of your project, create a new &lt;code&gt;.js&lt;/code&gt; file called &lt;code&gt;nimbus-team.js&lt;/code&gt;. Add the following to this file:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NimbusTeam&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; #selectors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;UserCardTmpl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nimbus-team-user-card-tmpl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  #shadow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; template &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      NimbusTeam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#selectors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UserCardTmpl&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;template&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; template&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cloneNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#shadow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nimbus-team&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NimbusTeam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s break down what is happening here. We start by defining a class for our component and extending the &lt;code&gt;HTMLElement&lt;/code&gt; base class so that we can inherit from it. We set two private JavaScript properties (those marked with &lt;code&gt;#&lt;/code&gt;), one of which is marked as static.&lt;/p&gt;&lt;p&gt;Next, we define our constructor, and critically, we call &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Digging into the details of Classes in JavaScript is beyond the scope of this article. For more information please refer to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;documentation on MDN Web Docs&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;Next, we attach our  shadow DOM root to our component and store a reference in our private &lt;code&gt;#shadow&lt;/code&gt; property. Custom elements have several &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;life cycle events with associated predefined functions&lt;/a&gt; (this will sound very familiar to you if you have been using almost any of the popular frontend JavaScript frameworks).&lt;/p&gt;&lt;p&gt;Here we are using the &lt;code&gt;connectedCallback&lt;/code&gt; to insert the templates of our content into the shadow DOM we attached a little earlier. It is important to note that we do not simply get a reference to the &lt;code&gt;template&lt;/code&gt; element and insert it into the shadow DOM. What we need to do instead and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;clone the content of the template&lt;/a&gt; and then inject this into the shadow DOM.&lt;/p&gt;&lt;p&gt;Finally we register our custom element using &lt;code&gt;customElements.define&lt;/code&gt;. To avoid potential conflicts with native HTML element, custom element must always be hyphenated. The second argument to the function call is a reference to our class.&lt;/p&gt;&lt;p&gt;We need to do one more thing before we start seeing the fruits of our labor in the browser. Back in the HTML document, just before the closing &lt;code&gt;body&lt;/code&gt; tag, add the following &lt;code&gt;script&lt;/code&gt; element.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;js/nimbus-team.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-css&quot;&gt;The CSS&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-css&quot; aria-labelledby=&quot;the-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When you reload your browser, you will see our user card. Of course, it is a bit of a mess and completely unstyled right now.&lt;/p&gt;&lt;p&gt;I have provided the social media icon SVG files and the CSS, which you can &lt;a href=&quot;https://github.com/schalkneethling/shadow-core-html/commit/5869e332d7748a0fe191675791c6e17a3baa5550&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;find in this GitHub commit&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;With the CSS and icons in place, we can link the stylesheet in the &lt;code&gt;head&lt;/code&gt; of our HTML document.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;css/user-card.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you had reloaded the HTML page at this stage, absolutely nothing would have changed. But why? This result is because the shadow DOM is doing exactly what it is supposed to and what we want based on our second requirement.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;We want our CSS to be scoped to our card component but, we do not want to have to write our CSS in JavaScript and would prefer to have our component CSS in its own CSS source file.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The shadow DOM is encapsulated, and we cannot pierce it from the outside (see the note below). As such, the CSS has no effect. There are several ways to get our CSS to be part of the shadow DOM, but in this article, we will load and apply it using &lt;code&gt;fetch&lt;/code&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;There are ways to pierce the shadow DOM which can be incredibly useful, but for the purposes of this article I will not cover any of this. If you want to learn more, there is a short &lt;a href=&quot;https://open-wc.org/guides/knowledge/styling/styles-piercing-shadow-dom/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;article on the Open Web Components blog talking about this topic&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;fetching-the-css&quot;&gt;Fetching the CSS&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#fetching-the-css&quot; aria-labelledby=&quot;fetching-the-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Because we will fetch and apply our CSS using JavaScript, we can remove the &lt;code&gt;link&lt;/code&gt; element from the HTML, as it will not be needed. We will add the following function to our JavaScript to load and apply our CSS.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;async &lt;span class=&quot;token function&quot;&gt;#loadCSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; style &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;css/user-card.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#shadow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code here is rather simple. We create a &lt;code&gt;style&lt;/code&gt; element, load our CSS file using &lt;code&gt;fetch&lt;/code&gt; and if it was successful, we get the text from the response and set it as the text content of the &lt;code&gt;style&lt;/code&gt; element. Lastly we append the new &lt;code&gt;style&lt;/code&gt; tag to our shadow DOM.&lt;/p&gt;&lt;p&gt;There is one more thing: we need to call our new function. We can do this either in the constructor or the connected callback as long as it is called after the shadow DOM root has been attached. I opted for doing so in the constructor.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;#loadCSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reloading the page now will show a still rather broken card, but as you will note, some of our global CSS, notably the custom properties, have pierced the shadow DOM. If you read the linked post from earlier, this will be expected and is actually pretty neat!&lt;/p&gt;&lt;p&gt;We have met our second requirement, but if you look in the developer tools’ elements panel, you will notice that the browser is actually being pretty forgiving. 🙃 Right now, we are injecting a list element without a parent, which breaks our first requirement of clean, semantic, and accessible HTML&lt;/p&gt;&lt;p&gt;Let’s fix this.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;some-more-dom-manipulation&quot;&gt;Some more DOM manipulation&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#some-more-dom-manipulation&quot; aria-labelledby=&quot;some-more-dom-manipulation&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To fix our HTML, we will add the following to our &lt;code&gt;connectedCallback&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listContainer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ul&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;listContainer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;card-list&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;listContainer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With this, our DOM is fixed, but we have a problem. The &lt;code&gt;visually-hidden&lt;/code&gt; class from our global CSS file is not having any effect (as we would expect). To remedy this, we will unfortunately have to either load the global CSS file (not recommended) or duplicate the class into the CSS file we are already loading.&lt;/p&gt;&lt;p&gt;With this change (&lt;a href=&quot;https://github.com/schalkneethling/shadow-core-html/commit/d6191e342d7cd0d657be2d4294075e22a0386d7c&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;view the commit here on GitHub&lt;/a&gt;), we are getting close to our final implementation.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;loading-the-data&quot;&gt;Loading the data&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#loading-the-data&quot; aria-labelledby=&quot;loading-the-data&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To get some fictional data for our card and satisfy out next requirement, we will use a simple &lt;a href=&quot;https://github.com/schalkneethling/fake-user-api/tree/main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Netlify serverless function I spun up called Fictional Folks&lt;/a&gt;. We will first add a private Class property called &lt;code&gt;#users&lt;/code&gt; and then add a function to load and store our user data in this property.&lt;/p&gt;&lt;p&gt;The data for each card will come from an external API, so we need a way to load it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;#users&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;async &lt;span class=&quot;token function&quot;&gt;#loadUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;https://fictionalfolks.netlify.app/.netlify/functions/users?count=1&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#users &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With the above we will get one random user each time we reload our page. The code to actually update the user card with the data is quite a lot but there is nothing super interesting so, instead of listing all of it here, &lt;a href=&quot;https://github.com/schalkneethling/shadow-core-html/commit/2deb35f98541161a32166027370dfb853dfc5807&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;please review the commit on GitHub for all of the details&lt;/a&gt; (I do quite a bit of refactoring in the commit so, please read over the changes in the commit carefully).&lt;/p&gt;&lt;p&gt;You should now have a successfully rendered user card with all of the relevant data filled in and functional! You can also play around with the API call and see what happens when you load more than a single user.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;The API returns a maximum of three users, as that is all that is in the JSON dummy data. Feel free to contribute more. 🤘&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;a-fork-in-the-road&quot;&gt;A fork in the road&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#a-fork-in-the-road&quot; aria-labelledby=&quot;a-fork-in-the-road&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We have now reached the point where we will start to hit the limitations of this version of our web component. If we review the remaining requirements, we will quickly see that we cannot satisfy them.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We want to be able to access our card components with their data available, even if JavaScript is not available.&lt;/li&gt;&lt;li&gt;We want to be able to use our component during server-side rendering, as part of a statically generated site, or even in more traditional server based frameworks such as those mentioned in the note earlier in this article.&lt;/li&gt;&lt;li&gt;We would very much appreciate a great developer experience that allows for ease of implementation and maintainability.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;On the last item, I will leave it up to you to determine how close or far we are from a great developer experience. While the experience thus far has definitely not been terrible, it has not been stellar either. To be honest, there is quite a bit one can do to optimize some of the code, but we will definitely still be left wanting.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;declarative-shadow-dom-to-the-rescue&quot;&gt;Declarative shadow DOM to the rescue!&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#declarative-shadow-dom-to-the-rescue&quot; aria-labelledby=&quot;declarative-shadow-dom-to-the-rescue&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Before we dig into this part, I want to make clear that I will primarily share the coding parts that change. I will link to the repository with the full code, but to not stretch out this post, I will refrain from sharing all of the step-by-step details where they are not absolutely required.&lt;/p&gt;&lt;p&gt;Also, for this part I will hard code the data for the user card but, I will also link to an example where I use the same declarative component within the context of an Astro project where the data and construction of the cards will happen at build time.&lt;/p&gt;&lt;p&gt;With those stated caveats, let’s refactor!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-template&quot;&gt;The template&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-template&quot; aria-labelledby=&quot;the-template&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We will change two things concerning our &lt;code&gt;template&lt;/code&gt; element.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We will move it inside our custom element&lt;/li&gt;&lt;li&gt;Remove the &lt;code&gt;id&lt;/code&gt; attribute and instead add the &lt;code&gt;shadowrootmode&lt;/code&gt; attribute&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;shadowrootmode&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;open&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card-list&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Marlowe Solace&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          ...&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-card-social&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon icon-social-bsky&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://bsky.app/profile/marlowe.solace&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;_blank&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;noopener noreferrer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Follow MArlowe on Bluesky&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            ...&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;You can review the&lt;a href=&quot;https://github.com/schalkneethling/neo-shadow-html/commit/38e4b31d898c93d6df2fb0a61516dfac60fb2aff#diff-0eb547304658805aad788d320f10bf1f292797b5e6d745a3bf617584da017051R16&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; full HTML as part of the following commit on GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;If you started a new HTML file for this part of the article, also make sure that you have linked the global CSS in the head as we did in our previous example. Now for the first mind-blown moment. If you open this file in your browser, you will see an unstyled instance of the card.&lt;/p&gt;&lt;p&gt;No JavaScript. &lt;strong&gt;What!?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;If we link the &lt;code&gt;user-card.css&lt;/code&gt; file in the &lt;code&gt;head&lt;/code&gt; and reload the page, you will still find that the CSS does not impact the card. What is happening here?&lt;/p&gt;&lt;p&gt;This is the beauty of declarative shadow DOM. The browser is simply ignoring the unknown &lt;code&gt;nimbus-team&lt;/code&gt; element and parsing the next line of HTML. The word &amp;quot;parsing&amp;quot; is critical here as this conversion from &lt;code&gt;template&lt;/code&gt; to &lt;code&gt;shadow-roo&lt;/code&gt;t happens through the HTML parser which is why we do not need any JavaScript yet and why this can now be part of a server-side rendered or statically generated website or application.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Although we are using our &lt;code&gt;template&lt;/code&gt; and &lt;code&gt;shadowrootmode&lt;/code&gt; in the context of a custom element in this article, this is not a rule. You can use a &lt;code&gt;template&lt;/code&gt; element with &lt;code&gt;shadowrootmode&lt;/code&gt; by itself to get the benefits of the encapsulation the shadow DOM provides. This is also why we get a &lt;code&gt;shadow-root&lt;/code&gt; even though our custom element is not yet known by the HTML parser.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;You can see this by inspecting the DOM using the elements panel of the browser developer tools.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z14-qJbqstJ98glW_shadow-dom-2.png?auto=format,compress&quot; alt=&quot;Shows the declaratively created shadow-root with the nested card list.&quot; /&gt;&lt;figcaption&gt;Shows the declaratively created shadow-root with the nested card list.&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-shadow-and-the-custom-element&quot;&gt;The Shadow and the Custom Element&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-shadow-and-the-custom-element&quot; aria-labelledby=&quot;the-shadow-and-the-custom-element&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Something else is also happening, though, as soon as we register our custom element, so let’s do that. Feel free to create a new blank JavaScript file as we will need very little of the previous JavaScript. All that is in my &lt;code&gt;.js&lt;/code&gt; file now is the following:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NimbusTeam&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nimbus-team&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NimbusTeam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that we have not called &lt;code&gt;attachShadow&lt;/code&gt; anywhere in the script yet. And we will not need to. Because our static HTML is now being upgraded due to us registering the custom element, the browser has also already exposed the &lt;code&gt;shadow-root&lt;/code&gt; to the custom element.&lt;/p&gt;&lt;p&gt;This means adding the following to the code above will indeed return an instance of the &lt;code&gt;shadow-root&lt;/code&gt; and not &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is important to know that calling &lt;code&gt;this.attachShadow&lt;/code&gt; inside a custom element that already has a declarative &lt;code&gt;shadow-root&lt;/code&gt; attached will not throw an error. Instead, the Declarative Shadow Root will be emptied and returned. So, be careful here, as it literally means what it says. If you call &lt;code&gt;this.attachShadow&lt;/code&gt;, everything that was added to the &lt;code&gt;shadow-root&lt;/code&gt; during parsing will be removed, and you will need to rebuild the DOM for the shadow DOM. In other words, our entire unordered list and all of its children will be removed.&lt;/p&gt;&lt;p&gt;Although we can check for the existence of our &lt;code&gt;shadowRoot&lt;/code&gt; using &lt;code&gt;this.shadowRoot&lt;/code&gt; &lt;a href=&quot;https://github.com/WICG/webcomponents/issues/871&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;shadowRoot&lt;/code&gt; is now also exposed on &lt;code&gt;ElementInternals&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ElementInternals&lt;/a&gt;&lt;/code&gt; is an entirely other topic, but it essentially means we can do the following:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NimbusTeam&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; internals &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachInternals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; internals&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;shadow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// we can now safely attach out shadowRoot without worrying&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// that we will blow away any existing shadow DOM elements&lt;/span&gt;&lt;br /&gt;			shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nimbus-team&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NimbusTeam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Depending on your use case, you may or may not need to do any of the above. I would say that if you know that the underlying HTML uses declarative shadow DOM, you can assume that a &lt;code&gt;shadowRoot&lt;/code&gt; will exist and can proceed. The one use case where you may need to do this is if you need to support browsers that do not yet support declarative shadow DOM.&lt;/p&gt;&lt;p&gt;The folks over at Salesforce did quite a deep dive into &lt;a href=&quot;https://github.com/salesforce/lwc-rfcs/blob/master/text/0129-declarative-shadow-dom-polyfill.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;polyfilling declarative shadow DOM&lt;/a&gt;, but there is also a simplified polyfill available in the &lt;a href=&quot;https://web.dev/articles/declarative-shadow-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Declarative Shadow DOM post on Web.Dev&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you choose not to go with a polyfill, remember that in instances where declarative shadow Dom is not supported, the original &lt;code&gt;template&lt;/code&gt; element will still be present in the DOM and can, therefore, be referenced, cloned, and inserted into the manually created &lt;code&gt;shadow-root&lt;/code&gt; (this means you may want to keep the &lt;code&gt;id&lt;/code&gt; attribute around for this purpose—choose your own adventure 🙃).&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;css-in-the-declarative-shadow&quot;&gt;CSS in the Declarative Shadow&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#css-in-the-declarative-shadow&quot; aria-labelledby=&quot;css-in-the-declarative-shadow&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You may be a little disappointed here because all we need to do to get our CSS to work and be scoped to our component is to take the &lt;code&gt;link&lt;/code&gt; element that is currently in the &lt;code&gt;head&lt;/code&gt; and move it into the &lt;code&gt;template&lt;/code&gt; element like so:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;shadowrootmode&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;open&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;css/user-card.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    ...&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nimbus-team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With this, you can go ahead and reload the page. As before, though, the &lt;code&gt;visually-hidden&lt;/code&gt; class is not going to pierce our shadow, and we will need to copy it into our user card CSS file. To further prove to ourselves that our component is isolated and that only CSS we want to pierce the shadow get through and nothing leaks out, add the following to the HTML just before the custom element:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Marlowe Solace outside the Shadow&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;global.css&lt;/code&gt; add the following:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And inside &lt;code&gt;user-cards.css&lt;/code&gt; change &lt;code&gt;.user-card-title&lt;/code&gt; to &lt;code&gt;h2&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--typography-font-size-heading&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When you reload the page, you will see that the outer heading is not affected by the &lt;code&gt;font-size&lt;/code&gt; setting inside the &lt;code&gt;user-card&lt;/code&gt; and is &lt;code&gt;hotpink&lt;/code&gt;. You will also notice that the &lt;code&gt;h2&lt;/code&gt; inside our component is our dark purple color and not &lt;code&gt;hotpink&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;conclusion-embracing-declarative-shadow-dom&quot;&gt;Conclusion: Embracing Declarative Shadow DOM&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#conclusion-embracing-declarative-shadow-dom&quot; aria-labelledby=&quot;conclusion-embracing-declarative-shadow-dom&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Web components have always promised reusable, isolated, and standards-based solutions for building modern web applications. Yet, challenges like server-side rendering (SSR), static site generation (SSG), performance, and accessibility have often kept developers reliant on frameworks and custom solutions. Declarative Shadow DOM bridges these gaps, unlocking the full potential of web components for the modern web platform.&lt;/p&gt;&lt;p&gt;By simplifying integration with SSR and SSG, Declarative Shadow DOM makes web components more approachable, scalable, and powerful across a variety of tools and frameworks. Whether you’re working with JavaScript-based solutions like Astro or React, or traditional server-side frameworks like Django or Laravel, the benefits are clear: faster load times, improved developer experience, and seamless browser parsing of components.&lt;/p&gt;&lt;p&gt;Now it’s your turn to explore Declarative Shadow DOM! Try implementing it in your next project or experiment with the provided demos to see how it can transform your workflow. Start small with a simple component or take a bold step by integrating it into your production-ready web applications.&lt;/p&gt;&lt;p&gt;Check out the demo repositories linked below, and don’t forget to share your feedback and experiments. Let’s build the future of the web—declaratively. 🚀&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;some-common-questions&quot;&gt;Some common questions&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#some-common-questions&quot; aria-labelledby=&quot;some-common-questions&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;what-about-including-the-same-component-with-the-same-css-multiple-times-on-the-same-page&quot;&gt;What about including the same component with the same CSS multiple times on the same page?&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#what-about-including-the-same-component-with-the-same-css-multiple-times-on-the-same-page&quot; aria-labelledby=&quot;what-about-including-the-same-component-with-the-same-css-multiple-times-on-the-same-page&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This is not a problem at all, and browsers are highly optimized for this exact case. To &lt;a href=&quot;https://web.dev/articles/declarative-shadow-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;quote from the article on web.dev&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The browser uses a single backing &lt;code&gt;CSSStyleSheet&lt;/code&gt; that is shared by all of the shadow roots, eliminating duplicate memory overhead.&lt;/p&gt;&lt;/blockquote&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;what-about-a-flash-of-unstyled-content-fouc&quot;&gt;What about a Flash Of Unstyled Content (FOUC)?&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#what-about-a-flash-of-unstyled-content-fouc&quot; aria-labelledby=&quot;what-about-a-flash-of-unstyled-content-fouc&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This is another problem that goes away with declarative shadow DOM. Should you need or prefer to support browsers in which declarative shadow DOM is not supported, I would recommend that you &lt;a href=&quot;https://web.dev/articles/declarative-shadow-dom#how_to_avoid_the_flash_of_unstyled_content&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;read the section in the web.dev article&lt;/a&gt; that touches on this very topic.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;could-you-generate-the-template-server-side-for-non-declarative-shadow-dom&quot;&gt;Could you generate the template server side for non-declarative shadow DOM?&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#could-you-generate-the-template-server-side-for-non-declarative-shadow-dom&quot; aria-labelledby=&quot;could-you-generate-the-template-server-side-for-non-declarative-shadow-dom&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You surely can, but your content will still not be available in the following cases:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;JavaScript fails or is not executed at all&lt;/li&gt;&lt;li&gt;Search engine indexing&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;To clarify the second point here. As of the writing of this post at the tail-end of 2024, only Google’s crawler will crawl with JavaScript enabled for indexing when needed. None of the other large search engines that maintain their own index does this. This means that the content inside the &lt;code&gt;template&lt;/code&gt; element will not be indexed.&lt;/p&gt;&lt;p&gt;There may also be some performance impacts to consider should one be cloning multiple large &lt;code&gt;template&lt;/code&gt; elements and inserting them into the DOM. I have not done extensive testing in this regard, but it is something to keep in mind.&lt;/p&gt;&lt;p&gt;You can &lt;a href=&quot;https://github.com/schalkneethling/shadow-core&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;try out an example of this in the Shadow Core example project&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;demo-projects&quot;&gt;Demo projects&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#demo-projects&quot; aria-labelledby=&quot;demo-projects&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As part of writing this article, I created several example projects that demonstrate using web components using the different approaches outlined here. Below is a list of these along with a short description of each.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;shadow-core-html&quot;&gt;Shadow Core HTML&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#shadow-core-html&quot; aria-labelledby=&quot;shadow-core-html&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As the name suggests, this one is a pure HTML implementation with no framework. This one also does not use Declarative ShadowDOM.&lt;/p&gt;&lt;p&gt;Find the code and the live example below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/schalkneethling/shadow-core-html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Shadow Core HTML repository on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://schalkneethling.github.io/shadow-core-html/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Experiment with Shadow Core HTML live&lt;/a&gt; (&lt;a href=&quot;https://pages.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deployed with GitHub pages&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;shadow-core&quot;&gt;Shadow Core&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#shadow-core&quot; aria-labelledby=&quot;shadow-core&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This example project is the same as the above but implemented using Astro. This means that the page is generated during the build phase and then upgraded using JavaScript on the client. Try disabling JavaScript and reloading the page.&lt;/p&gt;&lt;p&gt;Find the code and the live example below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/schalkneethling/shadow-core&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Shadow Core repository on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://schalkneethling.github.io/shadow-core/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Experiment with Shadow Core live&lt;/a&gt; (&lt;a href=&quot;https://pages.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deployed with GitHub pages&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;neo-shadow-html&quot;&gt;Neo-Shadow HTML&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#neo-shadow-html&quot; aria-labelledby=&quot;neo-shadow-html&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This is like Shadow Core HTML but uses Declarative ShadowDOM. Find the code and the live example below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/schalkneethling/neo-shadow-html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Neo-Shadow HTML repository on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://schalkneethling.github.io/neo-shadow-html/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Experiment with Neo-Shadow HTML live&lt;/a&gt; (&lt;a href=&quot;https://pages.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deployed with GitHub pages&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;neo-shadow&quot;&gt;Neo-Shadow&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#neo-shadow&quot; aria-labelledby=&quot;neo-shadow&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Are you seeing a pattern here? 🙈 This is the Declarative ShadowDOM variant implemented in Astro. Try disabling JavaScript and reloading the page.&lt;/p&gt;&lt;p&gt;Find the code and the live example below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/schalkneethling/neo-shadow&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Neo-Shadow repository on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://neoshadow.netlify.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Experiment with Neo-Shadow live&lt;/a&gt; (&lt;a href=&quot;https://www.netlify.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deployed with Netlify&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;neo-shadow-laravel&quot;&gt;Neo-Shadow Laravel&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#neo-shadow-laravel&quot; aria-labelledby=&quot;neo-shadow-laravel&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Same as the other two Neo-Shadow examples but implemented in &lt;a href=&quot;https://laravel.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Laravel&lt;/a&gt;. In this example, the content is hard coded in the controller, but you can imagine this coming from a database call and then returned. From a front-end and user experience perspective, this does not matter and the behavior will be the same. As with the Astro example, try disabling JavaScript and reloading the page.&lt;/p&gt;&lt;p&gt;Find the code and the live example below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/schalkneethling/neo-shadow-laravel&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Neo-Shadow Laravel repository on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://nml5ubwq53lnjguflaksenadh40fxapy.lambda-url.us-east-1.on.aws/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Experiment with Neo-Shadow Laravel live&lt;/a&gt; (&lt;a href=&quot;https://vapor.laravel.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deployed using Laravel Vapor&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-support-landscape&quot;&gt;The support landscape&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#the-support-landscape&quot; aria-labelledby=&quot;the-support-landscape&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://caniuse.com/shadowdomv1&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ShadowDOM support details on CanIUse&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://caniuse.com/declarative-shadow-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Declarative ShadowDOM support details on CanIUse&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://caniuse.com/template&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;HTML template support details on CanIUse&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://caniuse.com/custom-elementsv1&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Custom element support details on CanIUse&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/declarative-shadow-dom/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;An example Astro project with declarative shadow DOM loading data from a third-party API - &lt;a href=&quot;https://github.com/schalkneethling/neo-shadow/tree/main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;NeoShadow on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The HTML &lt;code&gt;template&lt;/code&gt; element on MDN Web Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/declarative-shadow-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Declarative Shadow DOM article on web.dev&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Web Components documentation on MDN Web Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components#custom_elements_2&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Custom elements reference on MDN Web Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components#shadow_dom_2&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Shadow DOM reference on MDN Web Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;ElementInternals&lt;/code&gt; documentation on MDN Web Docs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://schalkneethling.com/&quot;&gt;Schalk Neethling&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z141mJbqstJ98gjh_schalk-neethling.jpeg?auto=format,compress&amp;rect=0,0,480,480&amp;w=150&amp;h=150&quot; alt=&quot;Schalk Neethling&quot; /&gt;
  &lt;p&gt;Schalk Neethling is a passionate front-end engineer, podcast host, mentor, and open web and web accessibility evangelist. He strives to be a kind-hearted advocate for mental health and is committed to spreading kindness, mindfulness, and awareness about mental illness, devoid of stigma. His role as a mentor has shown him the joy of sharing knowledge and empowering others. He is dedicated to improving the world by amplifying voices with similar visions, striving to create a brighter future, one opportunity and voice at a time.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Schalk selected &lt;strong&gt;&lt;a href=&quot;https://www.paypal.com/donate/?hosted_button_id=VCREWCLA6WTB4&quot;&gt;Distribute Aid&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.paypal.com/donate/?hosted_button_id=VCREWCLA6WTB4&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/Z140tZbqstJ98gjf_distribute-aid.png?auto=format,compress&quot; alt=&quot;Distribute Aid&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Distribute Aid is a nonprofit that enhances humanitarian logistics by supporting grassroots aid organizations with scalable infrastructure. Its mission is to meet basic human needs through efficient aid delivery while empowering local communities.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS content-visibility</title>
    <link href="https://12daysofweb.dev/2024/css-content-visibility/"/>
    <updated>2024-12-17T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/css-content-visibility/</id>
    <content type="html">



&lt;p&gt;Newly available in Baseline 2024 is the content-visibility CSS property and as its name implies, it controls the visibility of an element’s content.&lt;/p&gt;&lt;p&gt;What makes this property different than selecting all of an element’s children and setting a rule for them like &lt;code&gt;display: none&lt;/code&gt; or &lt;code&gt;visibility: hidden&lt;/code&gt; is that content-visibility applies to &lt;em&gt;all of an element’s content&lt;/em&gt; — including text nodes and pseudo-content — not just child elements.&lt;/p&gt;


  
    

    
    &lt;p&gt;In the following demo, the visibility of the content is different due to the use of &lt;code&gt;display: none&lt;/code&gt; versus &lt;code&gt;content-visibility:hidden&lt;/code&gt;. Validate what&amp;#39;s happening by inspecting with browser dev tools.&lt;/p&gt;
    

    
    &lt;style&gt;
    .display-none &gt; * {
    display: none;
}

.content-hidden {
    content-visibility: hidden;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Comparison of using content-visibility&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.display-none &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.content-hidden&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;content-visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;display-none&quot;&gt;
    &lt;p&gt;This element is hidden.&lt;/p&gt;
    This is the only visible text because its a text node inside of display: none
&lt;/div&gt;

&lt;div class=&quot;content-hidden&quot;&gt;
    &lt;p&gt;This element is hidden.&lt;/p&gt;
    This text is also hidden.
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;It’s also different than having &lt;code&gt;display: none&lt;/code&gt; or &lt;code&gt;visibility: hidden&lt;/code&gt; directly applied to the element itself, since for those properties the entire box isn’t visible, while for &lt;code&gt;content-visibility&lt;/code&gt; its own box is generated and visible.&lt;/p&gt;&lt;p&gt;But there’s more to &lt;code&gt;content-visibility&lt;/code&gt; than just being a visibility on-off switch — it allows browsers to fully skip rendering for the contents. This means skipping style calculation, layout, and paint. The property is a power tool in a web author’s performance kit. Before we unwrap the syntax of &lt;code&gt;content-visibility&lt;/code&gt;, we need to talk about CSS containment.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;css-containment&quot;&gt;CSS Containment&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#css-containment&quot; aria-labelledby=&quot;css-containment&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you’ve used &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;container queries&lt;/a&gt;, then you’ve already encountered containment, whether you were aware of it or not.&lt;/p&gt;&lt;p&gt;Containment isolates a subtree of the document to improve performance and stability. This also allows features like container queries to exist since it helps avoid infinite loops.&lt;/p&gt;&lt;p&gt;There are four types of containment:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Size containment&lt;/strong&gt; ignores the element’s contents when determining its size.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Layout containment&lt;/strong&gt; prevents contents inside and outside from affecting each other’s layout. For example, &lt;code&gt;margin&lt;/code&gt; on content will not collapse with the parent’s margin (and therefore surrounding elements). Other features like baseline alignment do not affect an element with its layout contained.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Paint containment&lt;/strong&gt; clips any content from within the element that is protruding outside and isolates the content, which affects properties like &lt;code&gt;mix-blend mode&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Style containment&lt;/strong&gt; affects features like CSS counters: contained content cannot affect counters outside of the container.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Containments can be explicitly applied to an element using the &lt;code&gt;contain&lt;/code&gt; property. &lt;code&gt;container&lt;/code&gt; and &lt;code&gt;content-visibility&lt;/code&gt; both automatically apply the containments they need for their intended purpose.&lt;/p&gt;&lt;p&gt;Containment allows browsers to skip rendering an element’s contents when it’s hidden, which can improve performance, since the browser is free to focus on what’s relevant to the user. Browsers can also save rendering work, since the isolation created by containment makes rendering more predictable, improving the speed at which content can be hidden or made visible.&lt;/p&gt;&lt;p&gt;Now that we have a cursory understanding of containment let’s dig into &lt;code&gt;content-visibility&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-content-visibility&quot;&gt;Using content-visibility&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#using-content-visibility&quot; aria-labelledby=&quot;using-content-visibility&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are three values for &lt;code&gt;content-visibility&lt;/code&gt;: &lt;code&gt;visible&lt;/code&gt;, &lt;code&gt;hidden&lt;/code&gt;, and auto. We’ll explore how each works, but we’ll end up focusing on &lt;code&gt;auto&lt;/code&gt; as it’s extremely useful.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-initial-value-visible&quot;&gt;The initial value: visible&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#the-initial-value-visible&quot; aria-labelledby=&quot;the-initial-value-visible&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/initial_value&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;initial value&lt;/a&gt; of the property is &lt;code&gt;visible&lt;/code&gt;. When this is applied, no containments are applied to the element, and it has no performance optimizations. This is the regular old element you’re familiar with.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;manually-hiding-content-with-hidden&quot;&gt;Manually hiding content with hidden&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#manually-hiding-content-with-hidden&quot; aria-labelledby=&quot;manually-hiding-content-with-hidden&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;content-visibility: hidden&lt;/code&gt; hides the element’s contents and applies a strong set of containments to the element: size, layout, paint, and style. It’s very important to note that when &lt;code&gt;content-visibility&lt;/code&gt; is set to &lt;code&gt;hidden&lt;/code&gt; that content will be hidden from the accessibility tree and “find-in-page” browser features. Later we’ll touch on a couple of emerging web platform features that use &lt;code&gt;content-visibility: hidden&lt;/code&gt; and differ a small bit in this regard.&lt;/p&gt;&lt;p&gt;In this example, we’ve got the same box with content using both the &lt;code&gt;visible&lt;/code&gt; and &lt;code&gt;hidden&lt;/code&gt; values of &lt;code&gt;content-visibility&lt;/code&gt;. In the latter case, the box is still generated, but the content takes up no space.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;NPKNwLW&quot; data-user=&quot;knowler&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/knowler/pen/NPKNwLW&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;While the contents are hidden, it’s possible to measure them. This will trigger the browser’s rendering process for the contents, but the content will remain hidden.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;letting-the-browser-decide-using-auto&quot;&gt;Letting the browser decide using auto&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#letting-the-browser-decide-using-auto&quot; aria-labelledby=&quot;letting-the-browser-decide-using-auto&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When the &lt;code&gt;auto&lt;/code&gt; value is used, the browser hides the element’s contents while it’s not relevant to the user. This can serve as an easy performance win for many use cases.&lt;/p&gt;&lt;p&gt;Whether the contents are skipped for rendering or not, a set of containments is applied to the element:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;When the contents are rendered: layout, paint, and style containment are used on its containing element.&lt;/li&gt;&lt;li&gt;When the contents are skipped: layout, paint, style, and &lt;code&gt;size&lt;/code&gt; containment are used on its containing element.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;An important difference between &lt;code&gt;hidden&lt;/code&gt; and &lt;code&gt;auto&lt;/code&gt; is that &lt;code&gt;auto&lt;/code&gt; keeps the content in the accessibility tree and ensures it’s still findable with a browser’s “find-in-page” feature.&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;While writing this article, I discovered that Safari currently does not make skipped content findable for its “find-in-page” feature when &lt;code&gt;content-visibility: auto&lt;/code&gt; is used. If findability is critical for your use case, it’s probably best to wait until that’s fixed or avoid &lt;code&gt;content-visibility: auto&lt;/code&gt; in Safari for now. See &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=283846&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;WebKit Bug 283846&lt;/a&gt; to follow along.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;pairing-with-contain-intrinsic-size&quot;&gt;Pairing with contain-intrinsic-size&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#pairing-with-contain-intrinsic-size&quot; aria-labelledby=&quot;pairing-with-contain-intrinsic-size&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When &lt;code&gt;content-visibility&lt;/code&gt; is set to &lt;code&gt;hidden&lt;/code&gt; or &lt;code&gt;auto&lt;/code&gt;, and the element’s content is skipped, size containment is applied to the element. This means that the size of the element will be purely based on whatever dimensions are set for itself, its own padding, border-size, or the layout that it’s a part of. In many cases that’s not an issue, however, for some it can create problems. This is where the &lt;code&gt;contain-intrinsic-size&lt;/code&gt; property and its longhands can help.&lt;/p&gt;&lt;p&gt;Long, overflowing lists are a great use case for &lt;code&gt;content-visibility: auto&lt;/code&gt;, but that on its own can create some issues, as the scrollbar no longer becomes a reliable indicator of scroll progress.&lt;/p&gt;&lt;p&gt;In this example, we don’t have an intrinsic block-size for the element, so when it’s hidden the content take up no space which causes the scrollbar to be larger than what it would be if all of the list items are rendered. As the list items render, notice that the scrollbar changes sizes, getting smaller as it renders more items.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;NPKNawz&quot; data-user=&quot;knowler&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/knowler/pen/NPKNawz&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;If the block-size of the list items is consistent, we can set &lt;code&gt;contain-intrinsic-block-size&lt;/code&gt; to whatever the size of the content is.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;content-visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;contain-intrinsic-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, the content of each list item is stable, so we can set &lt;code&gt;contain-intrinsic-block-size&lt;/code&gt; to the &lt;code&gt;block-size&lt;/code&gt; of the content. Notice that the scroll remains stable and doesn’t jitter.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;XJrdeev&quot; data-user=&quot;knowler&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/knowler/pen/XJrdeev&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;In cases where there is no consistent size, but you have a good idea of what the average is, you can set &lt;code&gt;auto&lt;/code&gt; before that value, and this will cause the property to remember what its size was if it ever was rendered. Before then, it’ll use the other value as a fallback.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;content-visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;contain-intrinsic-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto 2lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, we don’t have a stable item size, so instead we’ve taken the average which we’ll use with &lt;code&gt;contain-intrinsic-block-size&lt;/code&gt; as a fallback. We’ve set &lt;code&gt;auto&lt;/code&gt; as the preferred which uses the last known rendered size as its value. Again, notice that the scrollbar mostly remains stable without jittering.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;KwPzXpe&quot; data-user=&quot;knowler&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/knowler/pen/KwPzXpe&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;When &lt;code&gt;content-visibility&lt;/code&gt; is used on elements within a complex layout, it can accidentally trigger undesirable layout reflow, when the content becomes visible again, and the size containment is dropped. This is another case where setting the intrinsic size of the contained element will help.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;what-makes-content-relevant&quot;&gt;What makes content relevant?&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#what-makes-content-relevant&quot; aria-labelledby=&quot;what-makes-content-relevant&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;content-visibility: auto&lt;/code&gt; doesn’t just render content when it’s on-screen; it’s a bit more nuanced than that: it renders content when it is considered relevant to the user. The following are conditions that make content relevant for the user:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The content is close to the viewport.&lt;/li&gt;&lt;li&gt;The content has an element with focus.&lt;/li&gt;&lt;li&gt;The content’s text is selected.&lt;/li&gt;&lt;li&gt;The content is in the top layer (i.e. the &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element and Popover API both use the “top layer” to keep their content on top of everything else).&lt;/li&gt;&lt;li&gt;The content is part of a view transition.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;observing-whether-content-is-skipped-with-javascript&quot;&gt;Observing whether content is skipped with JavaScript&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#observing-whether-content-is-skipped-with-javascript&quot; aria-labelledby=&quot;observing-whether-content-is-skipped-with-javascript&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You can listen for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/contentvisibilityautostatechange_event&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;contentvisibilityautostatechange&lt;/code&gt; event&lt;/a&gt; — yes, it’s a doozy to spell out. The event has a &lt;code&gt;skipped&lt;/code&gt; property which indicates when the content is currently skipped. While this is helpful for being able to confirm that the feature is indeed working, you can also use it to either start up or tear down expensive features depending on the skipped state (e.g. rendering on a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element or make network requests).&lt;/p&gt;&lt;p&gt;This is the same example we used for using an average intrinsic block-size for the elements, but I’ve included some JavaScript to log out whether elements are skipped using the &lt;code&gt;contentvisibilityautostatechange&lt;/code&gt; event, so make sure to view the console as you scroll the items.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;raBeJZB&quot; data-user=&quot;knowler&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/knowler/pen/raBeJZB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;I noticed a discrepancy between Chromium and other browsing engines where in Chromium this event bubbles, but for the other browsers it does not. This seems like it could be a spec issue. To follow along see &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/11310&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;issue #11310 in w3c/csswg-drafts on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-does-content-visibility-not-do&quot;&gt;What does content-visibility not do?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#what-does-content-visibility-not-do&quot; aria-labelledby=&quot;what-does-content-visibility-not-do&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While the &lt;code&gt;auto&lt;/code&gt; or &lt;code&gt;hidden&lt;/code&gt; value can skip rendering the content, this does not prevent resources such as images from downloading eagerly, so it’s a good idea to employ some sort of lazy-loading strategy alongside &lt;code&gt;content-visibility&lt;/code&gt;. That could look like using the &lt;code&gt;loading=lazy&lt;/code&gt; attribute.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;how-does-the-platform-use-content-visibility&quot;&gt;How does the platform use content-visibility?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#how-does-the-platform-use-content-visibility&quot; aria-labelledby=&quot;how-does-the-platform-use-content-visibility&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are a few emerging features in the web platform that use &lt;code&gt;content-visibility&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;details-content&quot;&gt;::details-content&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#details-content&quot; aria-labelledby=&quot;details-content&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One is &lt;a href=&quot;https://css-tricks.com/almanac/pseudo-selectors/d/details-content/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the ::details-content pseudo-element&lt;/a&gt;. This is a part of the &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element’s shadow tree — yes, many HTML elements are implemented with the Shadow DOM. &lt;code&gt;::details-content&lt;/code&gt; is a part-like pseudo-element that exposes the internal container element. In Chromium that container element is &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; which defaults to &lt;code&gt;display: contents&lt;/code&gt;, &lt;code&gt;::details-content&lt;/code&gt; sets the element as &lt;code&gt;display: block&lt;/code&gt; and then hides the content with &lt;code&gt;content-visibility: hidden&lt;/code&gt;. This means you can both style the element that houses the content and more easily animate it.&lt;/p&gt;&lt;p&gt;As of writing, this feature is only available in Chromium-based browsers (versions 131 and later — &lt;a href=&quot;https://caniuse.com/mdn-css_selectors_details-content&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;see &lt;code&gt;Can I use…&lt;/code&gt; for &lt;code&gt;::details-contents&lt;/code&gt; current availability&lt;/a&gt;).&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;hiddenuntil-found&quot;&gt;hidden=until-found&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#hiddenuntil-found&quot; aria-labelledby=&quot;hiddenuntil-found&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The other emerging feature is the &lt;code&gt;hidden=until-found&lt;/code&gt; attribute and value combination, which hides an element&amp;#39;s contents until it’s found using the “find-in-page” feature. Instead of setting &lt;code&gt;display: none&lt;/code&gt; for the element, the until-found value sets &lt;code&gt;content-visibility: hidden&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;As of writing, this feature is only available in Chromium-based browsers (versions 102 and later — &lt;a href=&quot;https://caniuse.com/mdn-html_global_attributes_hidden_until-found_value&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;see &lt;code&gt;Can I use…&lt;/code&gt; for &lt;code&gt;hidden=until-found&lt;/code&gt; current availability&lt;/a&gt;).&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;differences-with-content-visibility-hidden&quot;&gt;Differences with content-visibility: hidden&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#differences-with-content-visibility-hidden&quot; aria-labelledby=&quot;differences-with-content-visibility-hidden&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One important note for both of these features that is unlike how &lt;code&gt;content-visibility: hidden&lt;/code&gt; works by both hiding the content from the accessibility tree and “find-in-page” features, both the &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element and &lt;code&gt;hidden=until-found&lt;/code&gt; allow their content to be findable. Once found, the &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element expands, and the &lt;code&gt;hidden&lt;/code&gt; attribute is removed.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#summary&quot; aria-labelledby=&quot;summary&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let’s cover what we’ve learned:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;content-visibility&lt;/code&gt; makes it easy to hide content, completely skip rendering, and to opt-in to greater performance when we find ourselves in situations filled with content.&lt;/li&gt;&lt;li&gt;Having a grasp of CSS containment is important when using &lt;code&gt;content-visibility&lt;/code&gt; because it causes different types of containments to be applied to the element.&lt;/li&gt;&lt;li&gt;We can use another feature of the CSS containment suite, &lt;code&gt;contain-intrinsic-size&lt;/code&gt; and its longhands, to create an intrinsic size for elements with their contents skipped to avoid strange scrollbars or unexpected layout reflows.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/css-content-visibility/#further-reading&quot; aria-labelledby=&quot;further-reading&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you’re interested in learning more, I recommend checking out the following resources. Some of the included blog posts have great examples of &lt;code&gt;content-visibility&lt;/code&gt; being used in practice with lots of visual demonstrations and deep dives into the performance.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-contain-2/#content-visibility&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Containment Module Level 2 (spec)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;content-visibility on MDN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/content-visibility&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“content-visibility: the new CSS property that boosts your rendering performance” on web.dev&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“Improving rendering performance with CSS content-visibility” by Nolan Lawson&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/using-css-content-visibility-boost-rendering-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“Using CSS content-visibility to boost your rendering performance” on the LogRocket blog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://knowler.dev/&quot;&gt;Nathan Knowler&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z13KCpbqstJ98gN4_nathan-knowler.jpeg?auto=format%2Ccompress&amp;w=150&amp;h=150&quot; alt=&quot;Nathan Knowler&quot; /&gt;
  &lt;p&gt;Nathan is passionate about making the web for everyone. He’s interested in accessibility, progressive enhancement, and web components. When he’s not deep diving web specs or code spelunking, he can be found adventuring with his family in their frozen home of Winnipeg.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Nathan selected &lt;strong&gt;&lt;a href=&quot;https://www.indigenousfriends.org/&quot;&gt;Indigenous Friends Association&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.indigenousfriends.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.squarespace-cdn.com/content/v1/5e9f25e3009c0113ec06cca0/9a510018-d2dc-4767-b56f-c7df1d608463/IFA_Logo_text2_website.png?format=250w&quot; alt=&quot;Indigenous Friends Association&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Indigenous Friends Association is dedicated to cultivating digital pathways grounded in Indigenous ways of knowing and being. They create tech opportunities and bridge the digital divide for Indigenous communities.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS text-wrap</title>
    <link href="https://12daysofweb.dev/2024/css-text-wrap/"/>
    <updated>2024-12-16T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/css-text-wrap/</id>
    <content type="html">



&lt;p&gt;In print typography, a lot of attention is paid to line-breaking and text wrapping (among many other things).  In web typography, where we have no guarantee of line length, display area, or even font face, we’ve traditionally either ignored those things or hacked like mad scientists.  It’s all part of the Dao of web design, even if that does sometimes mean weirdly balanced text or hanging single words (&lt;a href=&quot;https://en.wikipedia.org/wiki/Widows_and_orphans&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;known as “runts”&lt;/a&gt;, at least sometimes).&lt;/p&gt;&lt;p&gt;But now, thanks to the shorthand property &lt;code&gt;text-wrap&lt;/code&gt; — I’ll break it apart into the longhand properties later — we can exert… well, &lt;code&gt;some&lt;/code&gt; influence.  Plus we can do things that we used to rely on &lt;code&gt;white-space&lt;/code&gt; to do.  For example, we can prevent text wrapping!&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1xkDZbqstJ98fJS_text-wrap-1.png?auto=format,compress&quot; alt=&quot;Figure 1. Text wrapping normally, and not wrapping at all.&quot; /&gt;&lt;figcaption&gt;Figure 1. Text wrapping normally, and not wrapping at all.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;code&gt;nowrap&lt;/code&gt;, as its name implies, prevents line-wrapping.  You can still use white-space: nowrap if that’s what your fingers’ muscle memory has programmed, so don’t worry about that going away.&lt;/p&gt;&lt;p&gt;Beyond that, &lt;code&gt;text-wrap&lt;/code&gt; offers two very welcome new values.  First up, you can have the browser &lt;code&gt;balance&lt;/code&gt; your element’s line lengths.  Compare the following example of &lt;code&gt;text-wrap: balance&lt;/code&gt; to the &lt;code&gt;text-wrap: wrap&lt;/code&gt; shown in Figure 1.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1xkEJbqstJ98fJV_text-wrap2.png?auto=format,compress&quot; alt=&quot;Figure 2. Balanced text wrapping.&quot; /&gt;&lt;figcaption&gt;Figure 2. Balanced text wrapping.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;There are no line-breaks or other extra bits in the HTML content.  Instead, the browser has looked at the element’s layout size and its content, and then shifted the line breaks around so that the individual lines of text are as close as possible to the same length.&lt;/p&gt;&lt;p&gt;You might think this would be computationally expensive, and you’re right, it is.  That’s the reason some browser engines limit the number of lines of text to which this can be applied: six for Chromium, and nine for Gecko.  WebKit, on the other hand, either doesn’t impose a limit, or has a limit higher than my testing could find (I went up to 25 lines).&lt;/p&gt;&lt;p&gt;Still, it’s really an effect to be used on headings, pull quotes, and other elements that will have enough content to run more than one line, but not so much content that they go past around five lines.&lt;/p&gt;&lt;p&gt;There’s also a way to have “normal” line wrapping while avoiding runts: &lt;code&gt;text-wrap: pretty&lt;/code&gt;.  Here’s a comparison of the default behavior to the “pretty” version.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1xkDpbqstJ98fJT_text-wrap-3.png?auto=format,compress&quot; alt=&quot;Figure 3. Preventing last-line loners with pretty wrapping.&quot; /&gt;&lt;figcaption&gt;Figure 3. Preventing last-line loners with pretty wrapping.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Here, the only line balancing is to avoid having the last line of text in the element have just one word.  You might have faked this in the past by replacing the last space in the element’s content with an &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt;.  Now, the CSS will just do it for you, at least in Chromium browsers; support has yet to land in WebKit and Gecko.&lt;/p&gt;&lt;p&gt;Be careful, though: just calling the wrapping &lt;code&gt;pretty&lt;/code&gt; does not guarantee pretty results, nor does it guarantee that you’ll never leave a lone word hanging at the end of an element.  Long words near the end of the content are a quick way to make things weird, as shown in Figure 4.&lt;/p&gt;&lt;figure class=&quot;figure-centered&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1xkD5bqstJ98fJU_text-wrap-4.png?auto=format,compress&quot; alt=&quot;Figure 4. Some limits of pretty wrapping.&quot; /&gt;&lt;figcaption&gt;Figure 4. Some limits of pretty wrapping.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;I would say the first example is better than the second, but either way, these are what pretty yielded.  It’s no worse than plain old &lt;code&gt;wrap&lt;/code&gt; behavior, but it’s not really any better either.&lt;/p&gt;&lt;p&gt;It should also be noted that pretty could do a lot more in the future.  The &lt;a href=&quot;https://www.w3.org/TR/2024/WD-css-text-4-20240529/#text-wrap&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;current-as-of-this-writing draft of the specification&lt;/a&gt; says that beyond just avoiding runts:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The precise set of improvements is user agent dependent, and may include things such as: reducing the variation in length between lines; avoiding typographic rivers; prioritizing different classes of soft wrap opportunities, hyphenation opportunities, or justification opportunities; avoiding hyphenation on too many consecutive lines…&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That’s the entire sentence — the ellipsis at the end there is part of it.  So this is a value that &lt;em&gt;could&lt;/em&gt; lead to rendering changes over time, should browser engines choose to do more.&lt;/p&gt;&lt;p&gt;As I said up top, &lt;code&gt;text-wrap&lt;/code&gt; is actually a shorthand property that encompasses the properties &lt;code&gt;text-wrap-mode&lt;/code&gt; and &lt;code&gt;text-wrap-style&lt;/code&gt;.  The values &lt;code&gt;wrap&lt;/code&gt; and &lt;code&gt;nowrap&lt;/code&gt; come from &lt;code&gt;text-wrap-mode&lt;/code&gt;, whereas &lt;code&gt;balance&lt;/code&gt; and &lt;code&gt;pretty&lt;/code&gt; come from &lt;code&gt;text-wrap-style&lt;/code&gt;.  The latter also has a value called &lt;code&gt;stable&lt;/code&gt;, which is defined to keep lines before the input cursor from re-flowing when the content is editable and being edited, but I couldn’t find any difference between &lt;code&gt;stable&lt;/code&gt; and &lt;code&gt;wrap&lt;/code&gt; behavior when I tested it.&lt;/p&gt;&lt;p&gt;So there you have it: text wrapping, all wrapped up for the holidays!  Whether you use it to prevent line-wrapping or make line lengths more consistent in headlines, &lt;code&gt;text-wrap&lt;/code&gt; and its longhands give us some welcome new options in text layout.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://meyerweb.com/&quot;&gt;Eric Meyer&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/8d036699-2569-471f-86f6-0faaeb9f0899_eric.jpeg?auto=format%2Ccompress&amp;rect=0%2C0%2C199%2C199&amp;w=150&amp;h=150&quot; alt=&quot;Eric Meyer&quot; /&gt;
  &lt;p&gt;CSS guy, author, speaker, Developer Advocate at Igalia.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Eric selected &lt;strong&gt;&lt;a href=&quot;https://www.stbaldricks.org/hero-funds/rebeccameyer/&quot;&gt;Rebecca’s Gift&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.stbaldricks.org/hero-funds/rebeccameyer/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://www.stbaldricks.org/photo/fund/26/large&quot; alt=&quot;Rebecca’s Gift&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The money raised by Rebecca’s Fund will be added to the St. Baldrick’s efforts to fund promising research in the prevention of tumor reemergence.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>HTML inert Attribute</title>
    <link href="https://12daysofweb.dev/2024/html-inert-attribute/"/>
    <updated>2024-12-15T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/html-inert-attribute/</id>
    <content type="html">



&lt;p&gt;While an element and its descendants with &lt;code&gt;inert&lt;/code&gt; are removed from the DOM, they will still be visible! Inert is meant to be applied to obscured elements that should not receive interaction events.&lt;/p&gt;&lt;p&gt;This is especially helpful if you want to &amp;quot;trap&amp;quot; focus to a particular part of your website.&lt;/p&gt;&lt;p&gt;Be aware that it is not the same as &lt;code&gt;display: none&lt;/code&gt; and &lt;code&gt;visibility: hidden&lt;/code&gt;, though, which makes elements disappear visually.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;explanation&quot;&gt;Explanation&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/html-inert-attribute/#explanation&quot; aria-labelledby=&quot;explanation&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;According to the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/interaction.html#the-inert-attribute&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;HTML specs&lt;/a&gt;, this is what &lt;code&gt;inert&lt;/code&gt; does:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The inert attribute is a boolean attribute that indicates, by its presence, that the element and all its flat tree descendants which don’t otherwise escape inertness (such as modal dialogs) are to be made inert by the user agent.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Translated into human language: An HTML element with the &lt;code&gt;inert&lt;/code&gt; attribute becomes &lt;em&gt;inactive&lt;/em&gt;, including all the (interactive) elements inside that element. They also go a bit more into detail how it should (and shouldn’t) be used:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;An inert subtree should not contain any content or controls which are critical to understanding or using aspects of the page which are not in the inert state.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Don’t use this attribute on a &lt;em&gt;parent element&lt;/em&gt; containing information or things like buttons, inputs or links that are important to understand or operate your website when there is no element visually blocking their use.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Content in an inert subtree will not be perceivable by all users, or interactive.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Anything inside an element with the &lt;code&gt;inert&lt;/code&gt; cannot be perceived or operated, which is the whole point of it.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Authors should not specify elements as inert unless the content they represent are also visually obscured in some way.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;If something is blocked by something or not visible at all, consider using &lt;code&gt;inert&lt;/code&gt;. If it cannot be perceived, maybe it should not be operable at all.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In most cases, authors should not specify the inert attribute on individual form controls. In these instances, the disabled attribute is probably more appropriate.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Use &lt;code&gt;inert&lt;/code&gt; on elements containing other elements to make larger sections inactive. If you want to disable something like a button, text field, checkbox, or radio button, use the &lt;code&gt;disabled&lt;/code&gt; attribute instead (this is a whole topic by itself; see &lt;a href=&quot;https://css-tricks.com/making-disabled-buttons-more-inclusive/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Making Disabled Buttons More Inclusive&lt;/a&gt; by Sandrina Pereira).&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;use-cases&quot;&gt;Use cases&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/html-inert-attribute/#use-cases&quot; aria-labelledby=&quot;use-cases&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For me, the most obvious use case would be when moving attention or focus to a dialog that just opened. As long as it is open, information and interactive elements outside of it are not available to the user. Of note, this is the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;default behaviour of the &amp;lt;dialog&amp;gt; element&lt;/a&gt; when using the &lt;code&gt;showModal()&lt;/code&gt; method.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Be aware that the behaviour of the &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element might be inconsistent across browsers and screen readers. Manuel Matuzović investigated it and offered some help to improve the user experience with this element: &lt;a href=&quot;https://www.matuzo.at/blog/2023/focus-dialog/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;O dialog focus, where art thou?&lt;/a&gt;&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;Another example: Say you provide a guided tour through your website to learn about different sections and UI elements. To ensure that keyboard users move from A to B to C and so on, you only enable the elements explaining something and the element(s) in question. The rest becomes inert!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;accessibility-considerations&quot;&gt;Accessibility considerations&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/html-inert-attribute/#accessibility-considerations&quot; aria-labelledby=&quot;accessibility-considerations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;inert&lt;/code&gt; is not:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Meant to disable interactive elements, this is what the &lt;code&gt;disabled&lt;/code&gt; attribute is for.&lt;/li&gt;&lt;li&gt;The same as &lt;code&gt;visibility: hidden&lt;/code&gt;, which only removes it visually but keeps it inside of the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/DOM&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;DOM&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Used for removing elements visually and from the DOM, like &lt;code&gt;display: none&lt;/code&gt;. Although if referenced from visible elements’ &lt;code&gt;aria-describedby&lt;/code&gt; or &lt;code&gt;aria-labelledby&lt;/code&gt; attribute they should still be exposed to assistive technologies.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;code&gt;inert&lt;/code&gt; is meant for making an HTML element (and all HTML elements inside of it) inactive, not focusable and ignored in the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Accessibility_tree&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;accessibility tree&lt;/a&gt; because the respective element is either partially or fully obscured.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/html-inert-attribute/#conclusion&quot; aria-labelledby=&quot;conclusion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Use inert on elements that are obscured and not entirely visibly hidden (like with &lt;code&gt;display: none&lt;/code&gt;), such as by some type of overlay that is intended to keep keyboard focus while open. This way you can provide a consistent experience for mouse, keyboard and assistive technology users.&lt;/p&gt;&lt;p&gt;Be aware that it is not the same as the disabled attribute or visibility: hidden.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/html-inert-attribute/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;HTMLElement: inert property&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;HTML attribute: disabled&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/display#none&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;display: none&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/visibility#hidden&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;visibility: hidden&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://stevefrenzel.dev/&quot;&gt;Steve Frenzel&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1xfaZbqstJ98fHb_steve-frenzel.jpg?auto=format,compress&amp;rect=0,0,666,666&amp;w=150&amp;h=150&quot; alt=&quot;Steve Frenzel&quot; /&gt;
  &lt;p&gt;Web developer &amp;amp; accessibility advocate from Germany. Loves HTML, CSS, JavaScript and hot sauces, in no particular order. Dog person but also cool with cats.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Steve selected &lt;strong&gt;&lt;a href=&quot;https://www.theasherhouse.com/&quot;&gt;The Asher House&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.theasherhouse.com/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://www.theasherhouse.com/cdn/shop/files/Screenshot_2024-01-19_at_9.02.19_AM_4600ce9f-fc40-49a1-aaeb-1e52b676b5b5.png?v=1717178956&amp;width=200&quot; alt=&quot;The Asher House&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;A registered non-profit sanctuary in Salem, Oregon. They rescue animals that have been discarded or unwanted, providing them with a life of comfort, love and adventure.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Animating Entry Effects</title>
    <link href="https://12daysofweb.dev/2024/animating-entry-effects/"/>
    <updated>2024-12-14T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/animating-entry-effects/</id>
    <content type="html">



&lt;p&gt;Animation is a critical component of interactive storytelling. An animation creates a journey, no matter how small, from point A to point B. &lt;/p&gt;&lt;p&gt;In classical animation, an artist draws one frame at a time, and a camera snaps a snapshot of each progression. For just one second of animation, 24 frames need to be drawn, captured, and sequenced. &lt;/p&gt;&lt;p&gt;For interactive content such as video games, web apps, and operating systems, players, visitors, and customers expect a stable 60 frames per second. Anything less than 60 individual images per second is perceptible to people with an eye tuned for it. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;css-animations&quot;&gt;CSS Animations &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#css-animations&quot; aria-labelledby=&quot;css-animations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With CSS, there are two primary properties used for animation: &lt;code&gt;transition&lt;/code&gt; and &lt;code&gt;animation&lt;/code&gt;. Both properties allow customization based on how long the animation should last (duration), when it should start (delay), and how the in-between frames should be &amp;quot;tweened&amp;quot; (easing). &lt;/p&gt;&lt;p&gt;Today, we will focus on a couple of aspects that can be utilized with the &lt;code&gt;transition&lt;/code&gt; property in CSS: &lt;code&gt;allow-discrete&lt;/code&gt; and &lt;code&gt;@starting-style&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;In the demo we&amp;#39;ll build, we will gracefully fade-in all content as it appears in our web document. &lt;/p&gt;&lt;p&gt;Before we go further, we need to take a step back and zoom out. &lt;/p&gt;&lt;p&gt;We know animation is a journey from point A to point B, but what are the technical terms for point A and point B? &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;keyframes&quot;&gt;Keyframes &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#keyframes&quot; aria-labelledby=&quot;keyframes&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A keyframe is the state of affairs at any moment in time. Given two states, we can calculate the difference between them and animate. This works great for things like numbers, but it doesn&amp;#39;t work great for non-number, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties#discrete&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;discrete CSS values&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;For example, there are a myriad of ways to not show a piece of content with CSS. Two of the more popular CSS properties are using opacity (continuous) and display (discrete). &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;opacity&quot;&gt;Opacity &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#opacity&quot; aria-labelledby=&quot;opacity&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Opacity is continuous and takes a value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;, inclusively. An opacity of &lt;code&gt;.5&lt;/code&gt; will be &lt;code&gt;50%&lt;/code&gt; transparent—you&amp;#39;ll be able to see the content behind the content. An opacity of &lt;code&gt;0&lt;/code&gt; is hidden, and &lt;code&gt;1&lt;/code&gt; is entirely visible. &lt;/p&gt;&lt;p&gt;If the opacity of point A is &lt;code&gt;0&lt;/code&gt; and the opacity of point B is &lt;code&gt;1&lt;/code&gt;, with an animation duration of &lt;code&gt;1000ms&lt;/code&gt;, the following statements are true. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;At 0ms, &lt;code&gt;opacity: 0&lt;/code&gt;&lt;/li&gt;&lt;li&gt;At 250ms, &lt;code&gt;opacity: .25&lt;/code&gt;&lt;/li&gt;&lt;li&gt;At 500ms, &lt;code&gt;opacity: .5&lt;/code&gt;&lt;/li&gt;&lt;li&gt;At 900ms, &lt;code&gt;opacity: .9&lt;/code&gt;&lt;/li&gt;&lt;li&gt;At 1000ms, &lt;code&gt;opacity: 1&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Writing each intermediate step out in code would be tedious, which is why the CSS engine tweens values on our behalf. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;display&quot;&gt;Display &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#display&quot; aria-labelledby=&quot;display&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Display values are discrete and may be defined as: inline, inline-block, flex, grid, inline-flex, inline-grid. All those properties will result in visible content. &lt;/p&gt;&lt;p&gt;Display may also be set to &lt;code&gt;none&lt;/code&gt;, hiding the content entirely. &lt;/p&gt;&lt;p&gt;Historically, CSS has not had a way to animate from a point A of &lt;code&gt;display: block&lt;/code&gt; to a point B of &lt;code&gt;display: none&lt;/code&gt; or of a point A of &lt;code&gt;display: none&lt;/code&gt; to a point B of any visible display type, such as &lt;code&gt;display: grid&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Animating between non-number discrete values, is hard. How can we do it?&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;code-and-demo&quot;&gt;Code and Demo&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#code-and-demo&quot; aria-labelledby=&quot;code-and-demo&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The following explanations will refer to this demo.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;MYgwpaz&quot; data-user=&quot;tylerchilds&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/tylerchilds/pen/MYgwpaz&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;using-allow-discrete&quot;&gt;Using allow-discrete&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#using-allow-discrete&quot; aria-labelledby=&quot;using-allow-discrete&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The transition property allows for a constituent property &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;transition-behavior&lt;/a&gt;&lt;/code&gt;, which may be set to &lt;code&gt;allow-discrete&lt;/code&gt;, which will allow CSS to animate between discrete values. &lt;/p&gt;&lt;p&gt;In this example, we apply the&lt;code&gt; transition-behavior&lt;/code&gt; of &lt;code&gt;allow-discrete&lt;/code&gt; to all elements. The &lt;code&gt;transition-properties&lt;/code&gt; we&amp;#39;re using are &lt;code&gt;visibility&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, and &lt;code&gt;opacity&lt;/code&gt;. Opacity and transform are both continuous properties that have been able to transition since &lt;code&gt;transition&lt;/code&gt; was implemented in CSS. Visibility is a discrete property and needs &lt;code&gt;allow-discrete&lt;/code&gt; to transition properly. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;using-starting-style&quot;&gt;Using @starting-style&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#using-starting-style&quot; aria-labelledby=&quot;using-starting-style&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In the example, notice the use of &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;@starting-style&lt;/a&gt;&lt;/code&gt;. This block is where we can define the initial keyframe we want to transition from. This is an opportunity for a new default value we, as web authors, define for our applications. &lt;/p&gt;&lt;p&gt;In the &lt;code&gt;@starting-style&lt;/code&gt; block, we select all elements with the wildcard selector and set the initial visibility to hidden with an &lt;code&gt;opacity&lt;/code&gt; of &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Note that it&amp;#39;s highly encouraged to wrap the rule in &lt;code&gt;@media (prefers-reduced-motion)&lt;/code&gt; to respect a user&amp;#39;s animation preferences.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;When the page loads, these will revert to their browser defaults of &lt;code&gt;visibility: visible&lt;/code&gt; and &lt;code&gt;opacity: 1&lt;/code&gt;, creating a smooth transition.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;exploring-opportunities&quot;&gt;Exploring Opportunities&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/animating-entry-effects/#exploring-opportunities&quot; aria-labelledby=&quot;exploring-opportunities&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;@starting-style&lt;/code&gt; and &lt;code&gt;transition-behavior: allow-discrete&lt;/code&gt; unlock the potential for animated storytelling that previously required JavaScript to achieve similar effects. With these tools now baked into CSS directly, how will you use them? &lt;/p&gt;&lt;p&gt;While the example in this demo is intentionally light to stay focused on the basics of these properties, a great first project might be to build a modal that can gracefully fade in and fade out. A common pitfall when implementing modals is for the hide animation to immediately hide with no animation, which generally happens when &lt;code&gt;visibility: hidden&lt;/code&gt; triggers, when the modal should instead hide at the end of the animation sequence. &lt;/p&gt;&lt;p&gt;By using &lt;code&gt;transition-behavior: allow-discrete&lt;/code&gt; when hiding the modal, other CSS or JavaScript workarounds that have historically been used for a smooth effect when hiding are no longer necessary.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://sillyz.computer/&quot;&gt;Tyler Childs&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1uYK5bqstJ98cmb_tyler-childs.jpg?auto=format,compress&amp;rect=0,0,320,320&amp;w=150&amp;h=150&quot; alt=&quot;Tyler Childs&quot; /&gt;
  &lt;p&gt;TyChi is the author of https://sillyz.computer, the children&amp;#39;s programming environment that powers the enterprise saas offering https://samesame.page. People ask where he has all the time to do this and know how to juggle so good and the short answer is, paper is the key to time travel. During spare time, TyChi teaches people how to traverse space time at the bowling alley or in the forest when other people are keeping the beat alive.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Tyler selected &lt;strong&gt;&lt;a href=&quot;https://archive.org/&quot;&gt;Internet Archive&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://archive.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/Z13KhpbqstJ98gN5_internet-archive-logo-white.png?auto=format,compress&quot; alt=&quot;Internet Archive&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Internet Archive&#39;s mission is universal access to all knowledge,  where they are most know for their keyframes across web space time  in the Wayback Machine.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>calc-size() and interpolate size</title>
    <link href="https://12daysofweb.dev/2024/calc-size-and-interpolate-size/"/>
    <updated>2024-12-13T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2024/calc-size-and-interpolate-size/</id>
    <content type="html">



&lt;p&gt;Animating to or from height: auto has been something front-end developers have had on their wishlist for a very long time, and now, not only can we do that very easily, but there are new possibilities that have opened up on top of that as well, all thanks to two new CSS features:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The interpolate-size property&lt;/li&gt;&lt;li&gt;The &lt;code&gt;calc-size()&lt;/code&gt; value function&lt;/li&gt;&lt;/ul&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;As of the time of writing, &lt;code&gt;interpolate-size&lt;/code&gt; and &lt;code&gt;calc-size&lt;/code&gt; are both only supported by Chrome and Edge. There are a lot of CodePen examples for you to see things in action, but I’ve also included videos in case you are using a different browser (do note that they have low fps).&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;all-you-need-is-one-line-of-css&quot;&gt;All you need is one line of CSS&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#all-you-need-is-one-line-of-css&quot; aria-labelledby=&quot;all-you-need-is-one-line-of-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The new &lt;code&gt;interpolate-size&lt;/code&gt; property enables animating to intrinsic sizes, such as &lt;code&gt;auto&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Here’s a simple example of it in action: We go from &lt;code&gt;block-size: 1lh&lt;/code&gt; to &lt;code&gt;block-size: auto&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;mybegom&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/mybegom&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/%20interpolate-1.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;enabling-it-site-wide-with-a-single-declaration&quot;&gt;Enabling it site-wide with a single declaration&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#enabling-it-site-wide-with-a-single-declaration&quot; aria-labelledby=&quot;enabling-it-site-wide-with-a-single-declaration&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The value of &lt;code&gt;interpolate-size&lt;/code&gt; is inherited, so we can enable it across our entire site with a single declaration.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;interpolate-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; allow-keywords&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That means with a single declaration, you’ve basically opted in to allow transitions and animations using keyword values site-wide!&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;This is perfect to include this as part of your CSS reset for new projects.&lt;/p&gt;&lt;p&gt;I’ve already started using this in a few places where I need to go from &lt;code&gt;block-size: 0&lt;/code&gt; to &lt;code&gt;block-size: auto&lt;/code&gt;, such as with navigations and menus.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;KwPVPpb&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/KwPVPpb&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/interpolate-2.mp4&quot;&gt;&lt;/video&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;If you are using this for elements with focusable elements inside of them, like a navigation, going to a &lt;code&gt;block-size: 0&lt;/code&gt; with an &lt;code&gt;overflow-hidden&lt;/code&gt; will visually hide the links, but they will still be accessible with keyboard navigation and through assistive technology like screen readers. You’ll have to take extra steps to ensure that it’s properly “closed.”&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;We can also use this to &lt;a href=&quot;https://codepen.io/kevinpowell/pen/OJKWMwO&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;animate details/summarys&lt;/a&gt;, though that also involves using &lt;code&gt;::details-content&lt;/code&gt;, which at the time of writing, has &lt;a href=&quot;https://caniuse.com/mdn-css_selectors_details-content&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;very limited support&lt;/a&gt;. Just like &lt;code&gt;calc-size()&lt;/code&gt; and &lt;code&gt;interpolate-size&lt;/code&gt;, it does make for a great progressive enhancement!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;its-not-just-for-height-auto&quot;&gt;It’s not just for height auto&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#its-not-just-for-height-auto&quot; aria-labelledby=&quot;its-not-just-for-height-auto&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While animating to and from &lt;code&gt;height: auto&lt;/code&gt; might be the most common pain point i&lt;code&gt;nterpolate-size&lt;/code&gt; solves, it also allows us to animate to any of these keyword values:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;auto&lt;/li&gt;&lt;li&gt;min-content&lt;/li&gt;&lt;li&gt;fit-content&lt;/li&gt;&lt;li&gt;max-content&lt;/li&gt;&lt;li&gt;content&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ZYzbZZZ&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/ZYzbZZZ&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/interpolate-3.mp4&quot;&gt;&lt;/video&gt;&lt;p&gt;&lt;strong&gt;However, you cannot use this to go between two different keyword values&lt;/strong&gt;, as you can see in this example where it doesn’t work.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;azovxez&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/azovxez&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;While that would be cool, I still see this as such a big win that I really don’t mind this one constraint.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-use-animations-as-well&quot;&gt;You can use animations as well&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#you-can-use-animations-as-well&quot; aria-labelledby=&quot;you-can-use-animations-as-well&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;All of the examples so far have used transitions, but this also opens up using keyword values in animations as well.&lt;/p&gt;&lt;p&gt;For example, instead of simply transitioning open to closed, we can add a nice little bounce effect.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ZYzbNzN&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/ZYzbNzN&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/interpolate-4.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;why-isnt-this-the-new-default&quot;&gt;Why isn’t this the new default?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#why-isnt-this-the-new-default&quot; aria-labelledby=&quot;why-isnt-this-the-new-default&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There were talks of having this be the default value, but there would be potential conflicts in older sites, such as situations where JavaScript was being used for these types of animations or where assumptions were made knowing transitions wouldn’t work in specific situations.&lt;/p&gt;&lt;p&gt;Because of this, &lt;strong&gt;I’d caution against blindly inserting this into older projects&lt;/strong&gt;. From now on, throw it in that reset and make animations super easy, but I wouldn’t retrofit it into an old project without some testing first.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;when-you-need-more-fine-grained-control&quot;&gt;When you need more fine-grained control&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#when-you-need-more-fine-grained-control&quot; aria-labelledby=&quot;when-you-need-more-fine-grained-control&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;interpolate-size&lt;/code&gt; is such a quick win, but you might find yourself running into situations where you want something a little bit bigger or smaller than one of the intrinsic sizes.&lt;/p&gt;&lt;p&gt;&lt;code&gt;calc()&lt;/code&gt; doesn’t allow for calculations based on keyword values, but another new addition is &lt;code&gt;calc-size()&lt;/code&gt;, which does!&lt;/p&gt;&lt;p&gt;The syntax of &lt;code&gt;calc-size()&lt;/code&gt; is a little trickier than that of &lt;code&gt;calc()&lt;/code&gt;, but once you get used to it, it’s not so bad.&lt;/p&gt;&lt;p&gt;The reason I say that it’s trickier is that you &lt;em&gt;must&lt;/em&gt; pass two values:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the intrinsic value that you want to use&lt;/li&gt;&lt;li&gt;the calculation you want to do to that size&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here are some examples:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.height-example&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size + 24px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.width-example&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;max-content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size * .5&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the first example above, I pass the keyword value that I want to do the calculation on (&lt;code&gt;auto&lt;/code&gt;), and then after the comma, I say to take whatever size value is computed and add &lt;code&gt;24px&lt;/code&gt; to it.&lt;/p&gt;&lt;p&gt;In the second example, I want the calculation to be based on the &lt;code&gt;max-content&lt;/code&gt; of my element and then multiplied by &lt;code&gt;0.5&lt;/code&gt; so that it becomes half that size.&lt;/p&gt;&lt;p&gt;Here is &lt;a href=&quot;https://codepen.io/kevinpowell/pen/ZYzbNBz&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;another simple example&lt;/a&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.max-content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; max-content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.bit-bigger-than-max-context&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;max-content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size + 3rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/Z1pJdpbqstJ98Xnc_calc-size.png?auto=format,compress&quot; alt=&quot;Preview of applied calc-size() where two text containers are shown, and the second is slightly longer visually due to the calc-size() rule&quot; /&gt;&lt;/p&gt;&lt;p&gt;For a bit more of a practical use case, in the example below, I use position absolute to move an SVG icon out of the flow and offset it to overflow to the right of the button that it is inside of. Then, using &lt;code&gt;calc-size()&lt;/code&gt; for the hover and focus states, I can add the distance I’ve offset the icon to the auto size of my button.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;WbeQVqK&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/WbeQVqK&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/interpolate-5.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;animations-and-transitions-with-calc-size&quot;&gt;Animations and transitions with calc-size()&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#animations-and-transitions-with-calc-size&quot; aria-labelledby=&quot;animations-and-transitions-with-calc-size&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While you might want to use &lt;code&gt;calc-size()&lt;/code&gt; for making something slightly bigger or smaller than one of the keyword values, just like interpolate-size, it also opens up animations and transitions on these values as well.&lt;/p&gt;&lt;p&gt;Below, I’ve updated the previous example to add a transition to the &lt;code&gt;inline-size&lt;/code&gt; of my button. Because I’m using a &lt;code&gt;calc size()&lt;/code&gt;, it works!&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;zxOvQRB&quot; data-user=&quot;kevinpowell&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kevinpowell/pen/zxOvQRB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/interpolate-6.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;calc-size-doesnt-require-interpolate-size&quot;&gt;calc-size() doesn’t require interpolate-size&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#calc-size-doesnt-require-interpolate-size&quot; aria-labelledby=&quot;calc-size-doesnt-require-interpolate-size&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When you use &lt;code&gt;calc-size()&lt;/code&gt;, transitions to and from intrinsic sizes will be allowed regardless of whether you’ve declared &lt;code&gt;interpolate-size: allow-keywords&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;You can see that in action in the previous example, where I didn’t declare &lt;code&gt;interpolate-size&lt;/code&gt;, and the transition still works.&lt;/p&gt;&lt;p&gt;That means that you could do something like this all on its own, and it’ll work as well:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.transition-height&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5lh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; clip&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; height 1s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.transition-height:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;However, it is recommended to use &lt;code&gt;interpolate-size&lt;/code&gt; for this instead.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It’s easier to simply “turn on” site-wide keyword animations and transitions and then rely on &lt;code&gt;calc-size()&lt;/code&gt; when you need to do actual calculations based on keyword values.&lt;/p&gt;&lt;p&gt;Also, it’s worth noting that, just like &lt;code&gt;interpoloate-size: allow-keywords&lt;/code&gt; doesn’t work for transtions or animations between keyword values, the same holds true with &lt;code&gt;calc-size()&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-interpolate-size-as-a-progressive-enhancement&quot;&gt;Using interpolate-size as a progressive enhancement&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2024/calc-size-and-interpolate-size/#using-interpolate-size-as-a-progressive-enhancement&quot; aria-labelledby=&quot;using-interpolate-size-as-a-progressive-enhancement&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If interpolate-size is not supported by a browser and you go from &lt;code&gt;block-size: 0&lt;/code&gt; to &lt;code&gt;block-size: auto&lt;/code&gt;, the browser will still switch between those two sizes, just without the transition between them. And to me, that makes it a perfect progressive enhancement.&lt;/p&gt;&lt;p&gt;People who are using browsers that support it get a nicer experience, but it won’t cause any issues for anyone using a browser that lacks support.&lt;/p&gt;&lt;p&gt;On the other hand, &lt;code&gt;calc-size()&lt;/code&gt; might be something you have to be more careful with, though.&lt;/p&gt;&lt;p&gt;For my buttons above, where I expanded them to show an icon, I wouldn’t really mind if a user didn’t see the icon because it doesn’t give extra value or context to the purpose of the button, but there are times when the extra size you are adding could be important or impact the layout in an important way.&lt;/p&gt;&lt;p&gt;In either case, it probably is a bit of a case-by-case basis, but I do think most cases of &lt;code&gt;interpolate-size&lt;/code&gt; would be fine. You might either have to think about it or provide alternatives with a &lt;code&gt;@supports&lt;/code&gt; feature query for &lt;code&gt;calc-size()&lt;/code&gt;.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://kevinpowell.co/&quot;&gt;Kevin Powell&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/40ae6422-2346-4999-ade4-229fc89a6fa7_kevin.webp?auto=format,compress&amp;rect=0,0,600,600&amp;w=150&amp;h=150&quot; alt=&quot;Kevin Powell&quot; /&gt;
  &lt;p&gt;Do my best to help people fall in love with CSS 😊&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Kevin selected &lt;strong&gt;&lt;a href=&quot;https://www.fondationstejustine.org/&quot;&gt;CHU Sainte-Justine Foundation&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.fondationstejustine.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-dark-filter&quot; src=&quot;https://www.fondationstejustine.org/app/themes/ste-justine-corpo-theme/public/images/logo_fr_voir_grand.svg&quot; alt=&quot;CHU Sainte-Justine Foundation&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Support CHU Sainte-Justine in its pursuit of excellence and its commitment to providing children and mothers with one of the highest levels of health care in the world, now and in the future.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Container Style Queries</title>
    <link href="https://12daysofweb.dev/2023/container-style-queries/"/>
    <updated>2023-12-24T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/container-style-queries/</id>
    <content type="html">



&lt;p&gt;One of the most requested features in CSS was &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;container queries&lt;/a&gt;, the ability to query the size of a parent container. Before container queries, you could only query the size of the viewport. That worked well and still does, allowing you to create responsive websites, but it&amp;#39;s really just a compromise because, in most cases, we&amp;#39;re interested in the size of our parent container, not the size of the viewport.&lt;/p&gt;&lt;p&gt;That’s why container queries are such a critical addition to CSS.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;For a general introduction to container queries, please visit &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Stephanie&amp;#39;s post&lt;/a&gt; since this post assumes that you already know the basics.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;In this example, when the &lt;code&gt;.cards&lt;/code&gt; container reaches a minimum width of &lt;code&gt;60rem&lt;/code&gt;, set the &lt;code&gt;flex-grow&lt;/code&gt; value of each &lt;code&gt;.card&lt;/code&gt; within the container to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.cards&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inline-size &gt; 60rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;flex-grow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I find container style queries even more interesting than container size queries because they could significantly change the way we think about and write CSS. Join me as we explore the reasons why.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-theory&quot;&gt;The Theory&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#the-theory&quot; aria-labelledby=&quot;the-theory&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The difference between size and style queries is that with style queries, you don&amp;#39;t query a &lt;a href=&quot;https://drafts.csswg.org/css-contain-3/#width&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;predefined list of features&lt;/a&gt; but use the &lt;code&gt;style()&lt;/code&gt; function to &lt;a href=&quot;https://drafts.csswg.org/css-contain-3/#style-container&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;query the value of a CSS property&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you wanted to apply styles to an element only when one of its parent elements has a display property with the value flex, you could do that by querying &lt;code&gt;style(display: flex)&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Here, when the &lt;code&gt;.cards&lt;/code&gt; container&amp;#39;s &lt;code&gt;display&lt;/code&gt; property is set to &lt;code&gt;flex&lt;/code&gt;, add a border to all but the &lt;code&gt;.card&lt;/code&gt; that is the &lt;code&gt;:last-child&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.cards&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cards&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; cards &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card:not(:last-child)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border-inline-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Unfortunately, I can&amp;#39;t provide you an interactive demo because style queries with normal properties aren&amp;#39;t supported in any browser and might never be because there are still &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/7185&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;concerns about its feasibility&lt;/a&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; At the moment of writing, the following demos only work in &lt;a href=&quot;https://caniuse.com/css-container-queries-style&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Chrome/Edge 111+ and Opera 98+&lt;/a&gt;. For the sake of readability, they don&amp;#39;t include any fallback logic.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-practice&quot;&gt;The practice&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#the-practice&quot; aria-labelledby=&quot;the-practice&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;What you can do today, at least in supporting browsers, is &lt;strong&gt;query custom properties&lt;/strong&gt;. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s take the following example: We have a red button, a regular section with a transparent background, and a highlighted section with the same red background as the button.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;KKJXGNX&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/KKJXGNX&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;The button works well in the regular section but almost vanishes in the highlighted section.&lt;/p&gt;&lt;p&gt;You could select all buttons in that section (&lt;code&gt;.section--highlight button&lt;/code&gt;) or create a class with alternative styling for buttons to work around the issue.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;xxMXyrB&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/xxMXyrB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;That works, but it&amp;#39;s a local solution to a global problem. It fixes the &lt;em&gt;bug&lt;/em&gt;, but it doesn&amp;#39;t solve your general issues:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If there are other buttons, you must also add the class.&lt;/li&gt;&lt;li&gt;Other elements, like links, will have the same or similar conflicts.&lt;/li&gt;&lt;li&gt;You&amp;#39;ll likely want to nest buttons in other containers with the same background color.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you&amp;#39;ve built larger, themeable systems, these problems are not news to you, and you know how to solve them.&lt;/p&gt;&lt;p&gt;One solution is to define custom properties on the highlighted section that descendants can inherit.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;qBgPJVz&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/qBgPJVz&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;That frees you from applying classes to your buttons and automates the process but also ties your button styles to the highlighted section, which doesn&amp;#39;t scale well, and you can’t reuse the button styles.&lt;/p&gt;&lt;p&gt;Container style queries offer a more global and systematic solution: You can add a container query that checks whether &lt;strong&gt;any parent element&lt;/strong&gt; has a red background color (&lt;code&gt;--container-bgc: var(--red)&lt;/code&gt;). If that&amp;#39;s the case, its descendant buttons get custom styles.&lt;/p&gt;&lt;p&gt;Please note, I&amp;#39;ve renamed the &lt;code&gt;--section&lt;/code&gt; and &lt;code&gt;—-body&lt;/code&gt; prefix to &lt;code&gt;--container&lt;/code&gt; to make it globally applicable.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;zYeEmRy&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/zYeEmRy&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;That&amp;#39;s already pretty great because the button styles change depending on the value of the &lt;code&gt;--container-bgc&lt;/code&gt; property and not on the kind of parent element.&lt;/p&gt;&lt;p&gt;The only problem with this solution is that you can&amp;#39;t reuse those alternative button styles elsewhere. You could try to make them reusable, similar to a mixin in Sass, by creating another query to apply them whenever a container has the &lt;code&gt;--button-style: secondary&lt;/code&gt; property and value.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Sets the buttons styles when a parent element has the custom property */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--button-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; secondary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--button-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--white&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--button-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Uses the button styles defined earlier when the background is red. */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--container-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--button-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; secondary&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That doesn&amp;#39;t work, though, because the properties in the first query apply if a parent element of the button has &lt;code&gt;--button-style: secondary&lt;/code&gt; set. Still, the second query sets the property on the button itself, not a parent element. &lt;/p&gt;&lt;p&gt;The absence of containers is a problem you&amp;#39;ll often face when working with container queries. &lt;a href=&quot;https://www.miriamsuzanne.com/who/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Miriam Suzanne&lt;/a&gt;, co-author of the containment specification, suggests Turtle Components™️ - elements that come with a shell (an extra container).&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shell --&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- new! 🐢 --&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shell --&gt;&lt;/span&gt;&lt;br /&gt;		  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- new! 🐢 --&gt;&lt;/span&gt;&lt;br /&gt;		    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Default section&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Let it snow!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;section--highlight&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shell --&gt;&lt;/span&gt;&lt;br /&gt;		  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- new! 🐢 --&gt;&lt;/span&gt;&lt;br /&gt;		    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Highlighted section&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;br /&gt;		    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Let it snow!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The content of each section is wrapped in an extra &lt;code&gt;div.container-inner&lt;/code&gt;, as well as the whole main content.&lt;/p&gt;&lt;p&gt;When the parent container has the right background color, styles apply to the inner container element.&lt;/p&gt;&lt;p&gt;In this update, we query the parent section, apply properties/settings to the &lt;code&gt;.container-inner&lt;/code&gt; div to which other queries can react.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;eYxGQrm&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/eYxGQrm&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;I know what you’re thinking: &amp;quot;That’s over-engineering par excellence! Why would you want to add so much complexity?&amp;quot;&lt;/p&gt;&lt;p&gt;For one, it scales well! If you add a completely different element with the same background color, its text and the button adapt accordingly. You don’t need any extra steps.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s an entirely new component with the same concept of default and highlighted background color.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I&#39;m a card&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lorem ipsum dolor sit.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Let it snow!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card card--highlight&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I&#39;m a card&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lorem ipsum dolor sit.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Let it snow!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Just set the background color and the button will adapt accordingly.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--container-bgc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card--highlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--container-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Admittedly, you could achieve a similar result by creating a helper class that does the same thing by setting all the necessary properties.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card h-theme--highlight&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	  …&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.h-theme--highlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--container-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--container-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--white&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--button-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--white&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--button-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can do that, and you might find it more intuitive, but like I said in the introduction, container style queries can change how you approach CSS. They enable you to reduce the dependency of the class as a middleman between your markup and your styles. Not that classes are bad in any way, but it&amp;#39;s worth exploring how you can automate the process of adding conditional styling to your components using classes in HTML by writing conditions in CSS.&lt;/p&gt;&lt;p&gt;You can even take it further and eliminate the modifier classes, and it would still work because your container queries look for custom properties on the element.   &lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--container-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container-inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Highlighted section&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Let it snow!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;wvNPdbq&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/wvNPdbq&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;If you want to support more colors, all you need to do is extend the query. This will apply custom styles if the background color is &lt;code&gt;red&lt;/code&gt; or &lt;code&gt;gray&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;OJdOgmz&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/OJdOgmz&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;If you want to add dark mode to your site, all you do is change the &lt;code&gt;--container-bgc&lt;/code&gt; property on the body.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--container-bgc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--gray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;eYxeRRa&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/eYxeRRa&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;The level of abstraction you pick depends on the size of your design system and who&amp;#39;s using it. Suppose you&amp;#39;re not the only one working with the components you build, but different teams and third parties. In that case, investing some extra work to create a resilient and flexible architecture that automates certain rules while improving the developer experience makes sense. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Container Style Queries may increase complexity for you, but they can decrease it for people using your components.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;use-cases&quot;&gt;Use cases&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#use-cases&quot; aria-labelledby=&quot;use-cases&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are also other use cases that work for projects of any size. Here are some examples.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;page-level-settings&quot;&gt;Page-level settings&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#page-level-settings&quot; aria-labelledby=&quot;page-level-settings&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Especially in large systems, but also on smaller sites you have different variations of page themes, layouts, and styles. With container queries, you can give authors a simple and human-readable way to tweak page styles.&lt;/p&gt;&lt;p&gt;For example, using custom properties on the root element to make decisions about the page’s theme and styles.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; rich&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can edit the CSS in this Pen directly in the light grey area.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;zYePdrK&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/zYePdrK&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;component-level-settings&quot;&gt;Component-level settings&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#component-level-settings&quot; aria-labelledby=&quot;component-level-settings&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You can provide a theming API for components.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--card-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; m&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* s, m, l */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--card-theme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* light, dark, colorful */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;oNmoepq&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/oNmoepq&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;inheritance&quot;&gt;Inheritance&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#inheritance&quot; aria-labelledby=&quot;inheritance&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The great thing about custom properties is that they&amp;#39;re inheritable. If you want to change the size of all cards in a container, you apply the settings to the container instead of each card separately.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cards&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--card-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or in CSS, where the &lt;code&gt;--card-size&lt;/code&gt; setting will apply to all nested cards.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.cards&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--card-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;wvNPraK&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/wvNPraK&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;relational-styles&quot;&gt;Relational styles&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#relational-styles&quot; aria-labelledby=&quot;relational-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Using the &lt;code&gt;:has()&lt;/code&gt; pseudo-class, you can apply styles to an element if it has a specific child element.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card:has(img) h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--gray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--white&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With container style queries, you can do a similar thing in CSS. In the following example, styles only apply if the element has a background image. You&amp;#39;re checking the existence of a particular property.&lt;/p&gt;&lt;p&gt;In this style query, the &lt;code&gt;.content&lt;/code&gt; gets a background color and a different text color when its parent element has a background image.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card-inner&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--card-background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&#39;background.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--card-background-image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--card-background-image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;30% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.2em 0.6em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;QWYxWvN&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/QWYxWvN&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;mixins&quot;&gt;Mixins&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#mixins&quot; aria-labelledby=&quot;mixins&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There is a &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/9350&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;proposal for mixins&lt;/a&gt;, but it still needs to be completed. With container style queries, you already have some of the functionality mixins would offer: reusability.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s take this simple media query. A small button becomes larger at a minimum width of &lt;code&gt;30em&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--font-size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.2rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--border-width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--border-color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* other button styles */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.6rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--border-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l - 10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; c h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you wanted to reuse those styles somewhere else, you&amp;#39;d have to repeat them.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn--large&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.6rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--border-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l - 10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; c h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Instead, you can create a custom property that takes those styles and puts them wherever you want.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Let it snow!&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--btn-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; large&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Let it snow!&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn--large&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Let it snow!&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--font-size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.2rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--border-width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--border-color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--btn-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; large&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.btn--large&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--btn-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; large&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--btn-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; large&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.6rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--border-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l - 10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; c h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;rNPKVja&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/rNPKVja&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;It&amp;#39;s not really a mixin because you can&amp;#39;t pass parameters, but you can reuse styles without duplicating them.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;summary-of-technicalities&quot;&gt;Summary of technicalities&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#summary-of-technicalities&quot; aria-labelledby=&quot;summary-of-technicalities&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Before we wrap this post, let me quickly summarize some technicalities that are worth knowing.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;type-and-name&quot;&gt;Type and Name&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#type-and-name&quot; aria-labelledby=&quot;type-and-name&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Every element is a style container; you don&amp;#39;t have to set the type explicitly.&lt;/p&gt;&lt;p&gt;A query always queries the closest parent container unless you provide a container name in the query.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- container &quot;page&quot; --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wrapper&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- container &quot;wrapper&quot; --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ho! Ho! ho!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--gray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;30% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--white&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--green&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.56 0.16 134.58&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--red&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.56 0.26 28.58&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.wrapper&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wrapper&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Evalutes to `true` because it is looking at&lt;br /&gt;the --style property on `main` */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; page &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px dotted&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;gOqKOaE&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/gOqKOaE&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;name-and-value&quot;&gt;Name and value&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#name-and-value&quot; aria-labelledby=&quot;name-and-value&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You can query custom properties without providing a value.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--card-background-image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;30% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* This would be possible if style queries would work with normal properties, too  */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;background-image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0% 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;comparison&quot;&gt;Comparison&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#comparison&quot; aria-labelledby=&quot;comparison&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When you&amp;#39;re comparing two unregistered custom properties, you are comparing &lt;a href=&quot;https://drafts.csswg.org/css-syntax-3/#typedef-hash-token&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;tokens&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The following query is true because you’re checking whether “red” is “red”.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Condition is true because `red === red`, styles applied */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px dotted fuchsia&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following query, however, is false because the string token &amp;quot;red&amp;quot; doesn&amp;#39;t equal the hash token &amp;quot;#F00&amp;quot;, although they represent the same color.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #F00&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Condition is false, styles not applied */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px dotted fuchsia&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To compare colors, you must register the property you’re querying as a &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@property&lt;/span&gt; --bg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;color&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; true&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;initial-value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Condition is true, styles applied */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px dotted fuchsia&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;GRzGRPR&quot; data-user=&quot;matuzo&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/matuzo/pen/GRzGRPR&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;Due to &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api/#substitution&quot; rel=&quot;noopener noreferrer&quot;&gt;property substitution&lt;/a&gt;, you don&amp;#39;t have to register the second property, as well.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/container-style-queries/#conclusion&quot; aria-labelledby=&quot;conclusion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One of the most significant downsides to some of the concepts I showed in this post is that you can&amp;#39;t query an element itself; you must query a container. That’s not so much a problem because of the extra divs you may have to add (you probably already have enough divs in your markup that you could use as containers anyway). It&amp;#39;s that in some situations, applying styles to a container isn&amp;#39;t intuitive. Sometimes, you&amp;#39;d want to apply them directly to an element.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--btn-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; funky&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(You can actually do that already by making use of Roma Komarov’s mind-boggling &lt;a href=&quot;https://kizu.dev/cyclic-toggles/&quot; rel=&quot;noopener noreferrer&quot;&gt;Cyclic Dependency Space Toggles&lt;/a&gt;.)&lt;/p&gt;&lt;p&gt;Nevertheless, container style queries are exciting and can make your lives or the lives of those using your components easier. At the moment, Chromium-based browsers are the only browsers that implement them. &lt;a href=&quot;https://www.notion.so/Container-Style-Queries-856caef9952b4de5b60d66e4b933dba9?pvs=21&quot; rel=&quot;noopener noreferrer&quot;&gt;Safari is willing to implement&lt;/a&gt;, but we have yet to learn about &lt;a href=&quot;https://github.com/WebKit/standards-positions/issues/57#issuecomment-1691159042&quot; rel=&quot;noopener noreferrer&quot;&gt;Mozilla&amp;#39;s position&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;So, please play around with container style queries, and if you like them, make some noise to convince other browser vendors of their usefulness.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://matuzo.at/&quot;&gt;Manuel Matuzovic&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/f7664b84-d829-4b39-b826-4e9dc1947874_manuel-matuzovic.jpeg?auto=compress,format&amp;rect=0,0,537,537&amp;w=150&amp;h=150&quot; alt=&quot;Manuel Matuzovic&quot; /&gt;
  &lt;p&gt;Manuel is a freelance frontend developer, accessibility auditor, teacher, and consultant who’s passionate about the web. He writes about accessibility, HTML, and CSS on his personal blog &lt;a href=&quot;https://matuzo.at/&quot; rel=&quot;noopener noreferrer&quot;&gt;matuzo.at&lt;/a&gt; and on &lt;a href=&quot;https://htmhell.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;htmhell.dev&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Manuel selected &lt;strong&gt;&lt;a href=&quot;https://www.frontlinedefenders.org/en/organization/sos-balkanroute&quot;&gt;SOSBalkanroute&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.frontlinedefenders.org/en/organization/sos-balkanroute&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-invert-filter&quot; src=&quot;https://www.frontlinedefenders.org/sites/default/files/sos_balkanroute_0.png&quot; alt=&quot;SOSBalkanroute&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;SOSBalkanroute is a humanitarian initiative for a dignified life for refugees in south-east Europe.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Responsive SVGs</title>
    <link href="https://12daysofweb.dev/2023/responsive-svgs/"/>
    <updated>2023-12-23T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/responsive-svgs/</id>
    <content type="html">



&lt;p&gt;SVG can be a tricky subject. If you&amp;#39;re a developer, you might need to have an interest in design to really dive into SVGs. And if you&amp;#39;re a designer, you&amp;#39;ll need to know a bit about coding to do more than just export files from design tools like Figma. This might be why we rarely see custom-made responsive SVGs, even though they are incredibly useful and versatile. In this post, I’ll guide you through the basics of creating a responsive SVG. &lt;/p&gt;&lt;p&gt;I was reminded of the potential of responsive SVGs when I looked at the Threads App. In the app, there&amp;#39;s an interesting design element where a little swirl line connects the avatar of a reply to the original message&amp;#39;s avatar. &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/9c1b31cf-8092-4d3f-b03e-046d25ee0cb1_image-01.png?auto=compress,format&quot; alt=&quot;A post from &amp;#39;zuck&amp;#39; from the Threads app showing a reply with a &amp;#39;swirl line&amp;#39; connecting the avatar of the reply to the original post.&quot; /&gt;&lt;/p&gt;&lt;p&gt;This design is achieved using three separate SVGs, with the length of the longest part calculated by JavaScript that is triggered on page load and every time the window is resized. While this is an effective approach, it relies heavily on JavaScript. In contrast, I want to show you how you can achieve a similar result using a responsive SVG and no JS at all.&lt;/p&gt;&lt;p&gt;To build the desired image, there are three basic things we need to understand: the &lt;code&gt;viewBox&lt;/code&gt; attribute, the &lt;code&gt;preserveAspectRatio&lt;/code&gt; attribute, and SVG symbols.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;viewbox-basics&quot;&gt;ViewBox Basics&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#viewbox-basics&quot; aria-labelledby=&quot;viewbox-basics&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 300 400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Think of the &lt;code&gt;viewBox&lt;/code&gt; in SVGs like an artboard in a design tool. For example, when you see &lt;code&gt;viewBox=&amp;quot;0 0 300 400&amp;quot;&lt;/code&gt;, it&amp;#39;s similar to saying, &amp;quot;Create an artboard that is 300 units wide and 400 units tall.&amp;quot; &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Remember, we&amp;#39;re working with vector graphics, so it&amp;#39;s best not to think in terms of pixels, as these graphics can be scaled to any size. &lt;/p&gt;&lt;p&gt;SVGs also have &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes, just like any other image. However, there&amp;#39;s a key difference: by default, SVGs behave as if &lt;code&gt;object-fit: contain&lt;/code&gt; is applied. This means if the aspect ratio set by &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; is different from the one defined by &lt;code&gt;viewBox&lt;/code&gt;, your &amp;quot;artboard&amp;quot; will always remain fully visible and maintain its proportions without distortion.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/78cd728d-6dac-4d48-97d1-eefa9987c11b_image-02.png?auto=compress,format&quot; alt=&quot;A diagram where an outer box with dimensions 600 wide by 400 high encompasses a viewBox area with the value &amp;#39;0 0 300 400&amp;#39; where the viewBox is centered in the outer box.&quot; /&gt;&lt;/p&gt;&lt;p&gt;To add a bit more complexity, you can actually choose not to define a &lt;code&gt;viewBox&lt;/code&gt; at all. When this happens, the actual width and height of the SVG itself become the dimensions of our &amp;quot;artboard.&amp;quot; This might sound a bit confusing now, but don&amp;#39;t worry; we&amp;#39;ll explore this in more detail later on.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;preserveaspectratio-object-fit&quot;&gt;PreserveAspectRatio ↔ Object-fit&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#preserveaspectratio-object-fit&quot; aria-labelledby=&quot;preserveaspectratio-object-fit&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 300 400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;preserveAspectRatio&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;xMaxYMin&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As I mentioned earlier, SVGs naturally act like they have &lt;code&gt;object-fit: contain&lt;/code&gt;. There&amp;#39;s also an attribute that functions similarly to &lt;code&gt;object-position&lt;/code&gt;: the &lt;code&gt;preserveAspectRatio&lt;/code&gt; property. &lt;/p&gt;&lt;p&gt;By default, it&amp;#39;s set to &lt;code&gt;preserveAspectRatio=&amp;quot;xMidYMid&amp;quot;&lt;/code&gt;, which centers the artboard. But you can change this setting to mimic other object-fit behaviors. For example, to replicate &amp;#39;object-fit: right top&amp;#39;, you would use &lt;code&gt;preserveAspectRatio=&amp;quot;xMaxYMin&amp;quot;&lt;/code&gt;. Remember, only one of these positioning rules will be applied due to the &amp;#39;contain&amp;#39; behavior. &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/ba747291-89a2-4ce6-b7fb-6c010992673e_image-03.png?auto=compress,format&quot; alt=&quot;A diagram where an outer box with dimensions 600 wide by 400 high encompasses a viewBox area with the value &amp;#39;0 0 300 400&amp;#39; and is aligned to the right half due to the application of preserveAspectRatio=&amp;#39;xMaxYMin&amp;#39;&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;svg-symbols&quot;&gt;SVG Symbols&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#svg-symbols&quot; aria-labelledby=&quot;svg-symbols&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we think of the &lt;code&gt;viewBox&lt;/code&gt; in SVGs as an artboard, SVG symbols are quite similar to components in design tools like Figma. Essentially, a symbol is like a small artboard within itself, which can be inserted (multiple times) within another SVG. Each symbol comes with its own &lt;code&gt;viewBox&lt;/code&gt; and &lt;code&gt;preserveAspectRatio&lt;/code&gt; attributes, defining the space and boundaries of this mini artboard. &lt;/p&gt;&lt;p&gt;To use an SVG symbol, you first define it with a &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; element, giving it a unique &lt;code&gt;id&lt;/code&gt;. This &lt;code&gt;symbol&lt;/code&gt; acts as a template. You can then place this template anywhere in your SVG with the &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; element, which references the symbol&amp;#39;s &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 300 400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;symbol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;symbol&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 20 30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		...&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- `href` equivalent to the `id` on the symbol --&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;use&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#symbol&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;building-a-responsive-svg&quot;&gt;Building a Responsive SVG&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#building-a-responsive-svg&quot; aria-labelledby=&quot;building-a-responsive-svg&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Before we put together our final SVG, let&amp;#39;s start with the swirl element, which we&amp;#39;ll later use as a symbol. &lt;/p&gt;&lt;p&gt;I began by creating an artboard with a width of &lt;code&gt;21&lt;/code&gt; and a height of &lt;code&gt;25&lt;/code&gt;, where I drew the swirl as a path. I set the path width to &lt;code&gt;2&lt;/code&gt; and chose to have round start and end points for a smooth appearance. To ensure symmetry, I positioned the start and end points of the curve such that their x-coordinates are both at &lt;code&gt;16&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/2bdf6d41-cf81-4c41-9906-67ff4a0f2d21_image-04.png?auto=compress,format&quot; alt=&quot;An illustration of the &amp;#39;swirl&amp;#39; using the dimensions and settings described in the previous paragraph. The loop of the swirl appears on the left side, with the two ends of the straight segments positioned in vertical alignment.&quot; /&gt;&lt;/p&gt;&lt;p&gt;The SVG code you get after exporting your design can vary depending on the graphic tool you use. Here&amp;#39;s what the code looked like when I exported my swirl design from Figma:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;g&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;url(#clip0_34_935)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;clipPath&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;clip0_34_935&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rect&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;white&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;clipPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There’s a lot of unnecessary stuff in there. Ultimately, we only need the path that defines the swirl. &lt;/p&gt;&lt;p&gt;I frequently rely on &lt;a href=&quot;https://jakearchibald.github.io/svgomg/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;SVG OMG&lt;/a&gt; by Jake Archibald to optimize my SVGs. However, Figma often includes a &lt;code&gt;clipPath&lt;/code&gt;, which, for our little demo at least, is not needed. Unfortunately, SVG OMG doesn&amp;#39;t remove it, so in the end, I manually removed everything except the path tag.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


  
    

    
    &lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;svg width=&quot;21&quot; height=&quot;25&quot; viewBox=&quot;0 0 21 25&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
	&lt;path d=&quot;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&quot; stroke=&quot;#FF0099&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;With our swirl asset prepared, we&amp;#39;re ready to construct the actual SVG. Let&amp;#39;s set a width of &lt;code&gt;21&lt;/code&gt; (the same width that is used for the swirl) and initially a height of &lt;code&gt;80&lt;/code&gt; for this SVG. As we discussed earlier, we&amp;#39;ll omit the &lt;code&gt;viewBox&lt;/code&gt; attribute.&lt;/p&gt;&lt;p&gt;In our SVG, we&amp;#39;ll define the swirl as a symbol within a &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; tag. To create this symbol, we can use most of the code from the swirl SVG we created. &lt;/p&gt;&lt;p&gt;The main changes involve replacing the &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tag with a &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; tag and removing the &lt;code&gt;xmlns&lt;/code&gt; attribute, as it&amp;#39;s not necessary for symbols. What we do need is an &lt;code&gt;id&lt;/code&gt; so it can be referenced within a &lt;code&gt;use&lt;/code&gt; tag.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Moving it into &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; as a &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; will prevent the path from being visible in the content.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;80&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;symbol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;swirl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make the swirl path visible, we must insert a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag that references this symbol. This is where the &lt;code&gt;preserveAspectRatio&lt;/code&gt; attribute comes into play. We want our swirl to always align at the bottom of the SVG, so we&amp;#39;ll apply &lt;code&gt;preserveAspectRatio=&amp;quot;xMidYMax&amp;quot;&lt;/code&gt; to the symbol. This ensures that the swirl is anchored to the middle bottom of the SVG. &lt;/p&gt;&lt;p&gt;Additionally, by setting the symbol&amp;#39;s height to &lt;code&gt;100%&lt;/code&gt; via the reference within &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;, we ensure that it always matches the height of the SVG, adapting fluidly to any changes in the SVG&amp;#39;s size.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;80&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;symbol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;swirl-1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;preserveAspectRatio&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;xMidYMax&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;use&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#swirl-1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;svg width=&quot;21&quot; height=&quot;80&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
	&lt;defs&gt;
		&lt;symbol id=&quot;swirl-1&quot; width=&quot;21&quot; height=&quot;25&quot; viewBox=&quot;0 0 21 25&quot; preserveAspectRatio=&quot;xMidYMax&quot; fill=&quot;none&quot;&gt;
			&lt;path d=&quot;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&quot; stroke=&quot;#FF0099&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot;&gt;&lt;/path&gt;
		&lt;/symbol&gt;
	&lt;/defs&gt;
	&lt;use href=&quot;#swirl-1&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;21&quot; height=&quot;100%&quot;&gt;&lt;/use&gt;
&lt;/svg&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;Now we have an SVG where the swirl is always positioned at the bottom, regardless of any height changes made through CSS. &lt;/p&gt;&lt;p&gt;Next, let&amp;#39;s add the long vertical line, which in the Threads App is the part with a dynamically calculated height. To do this, we&amp;#39;ll insert a rectangle that extends from the top to the bottom of the SVG. This is easily achieved by setting the rectangle&amp;#39;s height to &lt;code&gt;100%&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;80&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;symbol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;swirl-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;preserveAspectRatio&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;xMidYMax&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;use&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#swirl-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rect&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rx&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#f09&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;svg width=&quot;21&quot; height=&quot;80&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
	&lt;defs&gt;
		&lt;symbol id=&quot;swirl-3&quot; width=&quot;21&quot; height=&quot;25&quot; viewBox=&quot;0 0 21 25&quot; preserveAspectRatio=&quot;xMidYMax&quot; fill=&quot;none&quot;&gt;
			&lt;path d=&quot;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&quot; stroke=&quot;#FF0099&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot;&gt;&lt;/path&gt;
		&lt;/symbol&gt;
	&lt;/defs&gt;
	&lt;use href=&quot;#swirl-3&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;21&quot; height=&quot;100%&quot;&gt;&lt;/use&gt;
	&lt;rect x=&quot;15&quot; y=&quot;0&quot; width=&quot;2&quot; height=&quot;100%&quot; rx=&quot;1&quot; fill=&quot;#f09&quot;&gt;&lt;/rect&gt;
&lt;/svg&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;However, we don&amp;#39;t actually want our rectangle to extend the full 100% height of the SVG. Ideally, it should stop just where the swirl begins. &lt;/p&gt;&lt;p&gt;In SVG, you cannot define coordinates starting from the bottom, but we can cleverly use CSS to achieve the desired effect. By setting the rectangle&amp;#39;s height to &lt;code&gt;100% - 24px&lt;/code&gt;, we ensure that it reaches just above the swirl. This adjustment can be made directly within the SVG&amp;#39;s code. &lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;80&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;#swirl-4-rect&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 24px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;symbol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;swirl-4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 21 25&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;preserveAspectRatio&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;xMidYMax&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#FF0099&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;defs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;use&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#swirl-4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rect&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;swirl-4-rect&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rx&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#f09&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;svg width=&quot;21&quot; height=&quot;80&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
	&lt;style&gt;
		#swirl-4-rect {
			height: calc(100% - 24px);
		}
	&lt;/style&gt;
	&lt;defs&gt;
		&lt;symbol id=&quot;swirl-4&quot; width=&quot;21&quot; height=&quot;25&quot; viewBox=&quot;0 0 21 25&quot; preserveAspectRatio=&quot;xMidYMax&quot; fill=&quot;none&quot;&gt;
			&lt;path d=&quot;M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0&quot; stroke=&quot;#FF0099&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot;&gt;&lt;/path&gt;
		&lt;/symbol&gt;
	&lt;/defs&gt;
	&lt;use href=&quot;#swirl-4&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;21&quot; height=&quot;100%&quot;&gt;&lt;/use&gt;
	&lt;rect id=&quot;swirl-4-rect&quot; x=&quot;15&quot; y=&quot;0&quot; width=&quot;2&quot; height=&quot;100%&quot; rx=&quot;1&quot; fill=&quot;#f09&quot;&gt;&lt;/rect&gt;
&lt;/svg&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;And there you have it! We&amp;#39;ve successfully created a responsive SVG that adjusts its size while always keeping the swirl loop at the bottom, ensuring it doesn&amp;#39;t get distorted.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-responsive-svgs&quot;&gt;Using responsive SVGs&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#using-responsive-svgs&quot; aria-labelledby=&quot;using-responsive-svgs&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now, you might wonder, how do we actually use the swirl-line in our code? You have a few options. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;inline-svg&quot;&gt;Inline SVG&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#inline-svg&quot; aria-labelledby=&quot;inline-svg&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One of the simplest methods is to use it as an inline SVG. This approach allows you to define the symbol just once at the beginning of your document, rather than repeating it multiple times. Additionally, the style definition for the SVG can be included in your regular CSS stylesheet. It&amp;#39;s probably best to apply these styles using a specific class, to avoid affecting all rectangle elements globally.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;using-an-image-tag&quot;&gt;Using an image tag&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#using-an-image-tag&quot; aria-labelledby=&quot;using-an-image-tag&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You can also save the code as an SVG file and then use an image tag. Please note that for this approach, you have to delete the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes from the SVG and instead apply them to the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; Tag.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;css-in-svg-in-css&quot;&gt;CSS in SVG in CSS 🤯&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#css-in-svg-in-css&quot; aria-labelledby=&quot;css-in-svg-in-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Perhaps the most thrilling option available is embedding the SVG directly in our CSS as a data URI &lt;code&gt;background-image&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For this, I recommend a fantastic tool by &lt;a href=&quot;https://twitter.com/yoksel_en&quot; rel=&quot;noopener noreferrer&quot;&gt;@yoksel&lt;/a&gt;, which you can find at &lt;a href=&quot;https://yoksel.github.io/url-encoder/&quot; rel=&quot;noopener noreferrer&quot;&gt;https://yoksel.github.io/url-encoder/&lt;/a&gt;. This tool allows you to simply copy and paste any SVG and generates a ready-to-use code snippet for your stylesheet. You can then, for example, use a pseudo-element and apply the background image. &lt;/p&gt;&lt;p&gt;This process essentially embeds CSS within an SVG, which is then itself embedded within your CSS file. Isn&amp;#39;t that mind-blowing?&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#putting-it-all-together&quot; aria-labelledby=&quot;putting-it-all-together&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Check out this CodePen, where you&amp;#39;ll find all three examples demonstrated. While I don&amp;#39;t have a strong preference for any particular solution, I&amp;#39;m somewhat partial to the last option. The reason is, that it allows for the creation of the swirl without the need for an additional DOM element, which I find quite efficient and elegant.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;vYvExXv&quot; data-user=&quot;enbee81&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/enbee81/pen/vYvExXv&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;related-reading&quot;&gt;Related reading:&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/responsive-svgs/#related-reading&quot; aria-labelledby=&quot;related-reading&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.sarasoueidan.com/blog/svg-coordinate-systems/&quot; rel=&quot;noopener noreferrer&quot;&gt;Understanding SVG Coordinate Systems and Transformations&lt;/a&gt; by Sara Soueidan&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/svg-svg-viewbox&quot; rel=&quot;noopener noreferrer&quot;&gt;Understand the SVG Viewbox&lt;/a&gt; by Paul Ryan&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox&quot; rel=&quot;noopener noreferrer&quot;&gt;viewBox&lt;/a&gt; on mdn web docs&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;lt;symbol&amp;gt;&lt;/a&gt; on mdn web docs&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://ichimnetz.com/&quot;&gt;Nils Binder&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/8b840c01-59bb-45e2-af4e-137ff2561de9_nils.jpeg?auto=compress,format&amp;rect=351,0,492,492&amp;w=150&amp;h=150&quot; alt=&quot;Nils Binder&quot; /&gt;
  &lt;p&gt;Nils moves between two worlds — continuously striving to improve the communication between designers and developers. Starting as a so-called web-designer in 1999, he now calls himself &amp;quot;frontend designer.&amp;quot; He worked for a wide variety of clients, from startups to global players. Also, he&amp;#39;s an origami enthusiast spending hours folding paper.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Nils selected &lt;strong&gt;&lt;a href=&quot;https://queermentor.org/&quot;&gt;Queermentor&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://queermentor.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-invert-filter&quot; src=&quot;https://queermentor.org/assets/img/logo.svg&quot; alt=&quot;Queermentor&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Queermentor is committed to promoting equity by providing free mentoring, training, and networking opportunities for queer individuals. They also serve as a resource for companies looking to make a positive impact on the LGBTQIA+ community through their work.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>FileReader API</title>
    <link href="https://12daysofweb.dev/2023/filereader-api/"/>
    <updated>2023-12-22T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/filereader-api/</id>
    <content type="html">



&lt;p&gt;Ever wonder how websites claim to interpret an uploaded file &lt;em&gt;without&lt;/em&gt; storing any of your data? Admittedly, I used to be a bit skeptical myself. Enter the FileReader API! It allows a client-side application to asynchronously read and interpret an uploaded file. &lt;/p&gt;&lt;p&gt;In order to do this in your own client-side application, you&amp;#39;ll also want to learn about the File API and/or the Blob API. These are the &lt;em&gt;objects&lt;/em&gt; that you&amp;#39;ll &lt;em&gt;read&lt;/em&gt; with the FileReader API. You can also use the FileReader API to analyze files from a drag-and-drop operation.&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This isn&amp;#39;t to be confused with the much newer File System API, which provides the browser (and client-side JavaScript) access to your local file system.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;Although this API has been around for a while (Chrome started supporting it in version 6), parts of the modern usage haven&amp;#39;t been supported as long, such as the File API (shipped in Chrome 13) and the &lt;code&gt;File()&lt;/code&gt; constructor (shipped in Chrome 38).&lt;/p&gt;&lt;p&gt;In an almost ironic move, to test this API locally, you must serve the JavaScript from a secure domain (HTTPS), which can be done with several local tools or something like Codepen.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-basics&quot;&gt;The Basics&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/filereader-api/#the-basics&quot; aria-labelledby=&quot;the-basics&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The FileReader API, in basic usage, can be used in conjunction with &lt;code&gt;&amp;lt;input type=&amp;quot;file&amp;quot; /&amp;gt;&lt;/code&gt;. Once a file is either selected through the file browser &lt;em&gt;or&lt;/em&gt; dragged and dropped onto the file field, a new &lt;code&gt;File&lt;/code&gt; object is created on the input element. &lt;/p&gt;&lt;p&gt;&lt;code&gt;FileReader&lt;/code&gt; can be used with any &lt;code&gt;File&lt;/code&gt; object, but we’ll explore a basic usage scenario.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s try to pass the &lt;code&gt;File&lt;/code&gt; object to the &lt;code&gt;FileReader&lt;/code&gt; API like so:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fileReader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readAsText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above sample is not quite complete, however. The FileReader API is asynchronous by default and does not use promises. Instead, there are several events you can listen to. &lt;/p&gt;&lt;p&gt;For now, let&amp;#39;s focus on the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;load,&lt;/code&gt; which is fired when the file is loaded successfully&lt;/li&gt;&lt;li&gt;&lt;code&gt;error&lt;/code&gt;, which is fired when the file failed to be read&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fileReader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; resultContainer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;result&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;‘uploaded&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;file’&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readAsText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        resultContainer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;once&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice in the above example that we’re setting the text of the &lt;code&gt;resultContainer&lt;/code&gt; to the result that the &lt;code&gt;FileReader&lt;/code&gt; got once it fired the load event.&lt;/p&gt;&lt;p&gt;&lt;code&gt;result&lt;/code&gt; on the &lt;code&gt;fileReader&lt;/code&gt; object is exactly what you&amp;#39;d expect: whatever the &lt;code&gt;FileReader&lt;/code&gt; read from the file is contained in the &lt;code&gt;result&lt;/code&gt; property.&lt;/p&gt;&lt;p&gt;While it&amp;#39;s not able to read every type of file&amp;#39;s contents, the following methods are available for &lt;code&gt;FileReader&lt;/code&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;readAsText()&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;readAsDataURL()&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;readAsArrayBuffer()&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I&amp;#39;ll go through the first two in this article but know that this is a powerful API for a wide variety of applications.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;method-readastext&quot;&gt;Method: readAsText()&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/filereader-api/#method-readastext&quot; aria-labelledby=&quot;method-readastext&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;First up is the very basic text method FileReader API allows us to use. You&amp;#39;ll want only to use this method for smaller files, as it reads the entire file into memory. For larger files, you&amp;#39;ll want to use &lt;code&gt;readAsArrayBuffer()&lt;/code&gt;, as it returns a promise and is more predictable with larger files.&lt;/p&gt;&lt;p&gt;In the example above, we take the file we give &lt;code&gt;readFile()&lt;/code&gt; and log the result of the &lt;code&gt;readAsText&lt;/code&gt; method. This can be very useful if we want to interpret any kind of text-based file, such as &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.csv&lt;/code&gt;, etc.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;js,result&quot; data-slug-hash=&quot;KKJrovr&quot; data-user=&quot;clairebaire&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/clairebaire/pen/KKJrovr&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;method-readasdataurl&quot;&gt;Method: readAsDataURL()&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/filereader-api/#method-readasdataurl&quot; aria-labelledby=&quot;method-readasdataurl&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This method can be used for reading images, similar to how you&amp;#39;d interact with images if they were data-url strings. That is exactly what this method does: returns the image as a base64 encoded data-url.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: It is &lt;code&gt;readAsDataURL&lt;/code&gt; - with &lt;code&gt;URL&lt;/code&gt; all uppercase - not &lt;code&gt;readAsDataUrl&lt;/code&gt;. Using the latter will cause an error - it is case-sensitive.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s take the example below:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Don&#39;t forget to write &lt;span class=&quot;token constant&quot;&gt;HTML&lt;/span&gt; semantically&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file&quot;&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;uploaded-file&quot;&lt;/span&gt; onchange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;readImage()&quot;&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;uploaded-file&quot;&lt;/span&gt; accept&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;image/*&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    Upload an image&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;label&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice I am using the &lt;code&gt;accept&lt;/code&gt; attribute to limit the uploaded file to a MIME-type that is a type of image. Review &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept#unique_file_type_specifiers&quot; rel=&quot;noopener noreferrer&quot;&gt;how to specify file types&lt;/a&gt; to be accepted on MDN.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fileReader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;uploaded-file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readAsDataUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; resultContainer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        resultContainer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;once&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the above example, we&amp;#39;re:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;creating a &lt;code&gt;FileReader&lt;/code&gt;&lt;/li&gt;&lt;li&gt;then listening for when the &lt;code&gt;load&lt;/code&gt; event happens (meaning the file reading session was &lt;em&gt;successful&lt;/em&gt;)&lt;/li&gt;&lt;li&gt;then creating an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element and putting the image into the &lt;code&gt;src&lt;/code&gt; attribute as a data-url&lt;/li&gt;&lt;li&gt;finally, appending the created &lt;code&gt;img&lt;/code&gt; to the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; container we created for the images&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;js,result&quot; data-slug-hash=&quot;oNmQdyd&quot; data-user=&quot;clairebaire&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/clairebaire/pen/oNmQdyd&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;This API is great for simplistic things like in-browser manipulation or even real-time status updates while uploading the image / text / whatever the file might be to the backend server. Updating your profile picture on a major social network? You could replicate that with the FileReader API.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;filereader-events&quot;&gt;FileReader Events&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/filereader-api/#filereader-events&quot; aria-labelledby=&quot;filereader-events&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are several other events on the FileReader that are good to know. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;abort&lt;/code&gt; - a file read has been aborted (canceled)&lt;/li&gt;&lt;li&gt;&lt;code&gt;progress&lt;/code&gt; - fired periodically during a read&lt;/li&gt;&lt;li&gt;&lt;code&gt;loadstart&lt;/code&gt; / &lt;code&gt;loadend&lt;/code&gt; - can be used to trigger something at the beginning or the end of the loading of the file&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The events are extended from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent&quot; rel=&quot;noopener noreferrer&quot;&gt;ProgressEvent interface&lt;/a&gt;. By listening to the &lt;code&gt;progress&lt;/code&gt; event on FileReader, you can calculate file read progress by dividing the &lt;code&gt;loaded&lt;/code&gt; by the &lt;code&gt;total&lt;/code&gt; properties on the ProgressEvent.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;fileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; progress &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loaded &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Read progress: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;progress&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/filereader-api/#further-reading&quot; aria-labelledby=&quot;further-reading&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;FileReader is a great API that can be used for many client-side applications. It’s an underpinning of a lot of applications you might already use. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FileReader&quot; rel=&quot;noopener noreferrer&quot;&gt;FileReader API (MDN)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/js-file-reader&quot; rel=&quot;noopener noreferrer&quot;&gt;How to Read and Process Files with JavaScript FileReader API&lt;/a&gt; (DigitalOcean)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/File&quot; rel=&quot;noopener noreferrer&quot;&gt;File API (MDN)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot; rel=&quot;noopener noreferrer&quot;&gt;Blob API (MDN)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://front-end.social/@claire&quot;&gt;Claire Lipskey&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/e9fae8bd-a479-4442-b49d-aa5153e6889f_claire.jpeg?auto=compress,format&amp;rect=0,0,512,512&amp;w=150&amp;h=150&quot; alt=&quot;Claire Lipskey&quot; /&gt;
  &lt;p&gt;Claire is a front-end focused engineer passionate about standards-based solutions to the web’s problems. She lives in Chicago with her wife, elder cat and golden retriever puppy.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Claire selected &lt;strong&gt;&lt;a href=&quot;https://www.chicagowomenshealthcenter.org/&quot;&gt;Chicago Women&#39;s Health Center&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.chicagowomenshealthcenter.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/2587ab09-9e12-4880-802c-bcfbdfc65770_cwhc.jpeg?auto=compress,format&quot; alt=&quot;Chicago Women&#39;s Health Center&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;CWHC has practiced an approach to care that affirms clients and students, and ensures they have access to the information they need to decide what is best for their health and right for their bodies.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Scroll-driven Animations</title>
    <link href="https://12daysofweb.dev/2023/css-scroll-driven-animations/"/>
    <updated>2023-12-21T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/css-scroll-driven-animations/</id>
    <content type="html">



&lt;p&gt;One thing many fancy, award-winning websites have in common is they contain animations triggered by scrolling. Whether it’s a parallax effect, a progress bar animation, elements animating into view, or a full &lt;a href=&quot;https://webflow.com/blog/scrollytelling-guide&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;scrollytelling&lt;/a&gt; experience, on-scroll effects celebrate the medium of the web, clearly differentiating it from print. Indicating the progress of scroll can also be helpful to users.&lt;/p&gt;&lt;p&gt;Up until now, JavaScript has been a requirement for building scroll-driven animations. But the new &lt;a href=&quot;https://www.w3.org/TR/scroll-animations-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Scroll-driven Animations&lt;/a&gt; specification enables us to link the progress of an animation to the progress of scroll, all with just CSS. It’s a Christmas miracle!&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Please be aware scroll-driven animations are only supported in Chromium, or with a flag enabled in Firefox at the time of writing. To get the most out of this article, you’ll need to use a supporting browser.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;simple-use-animated-progress-indicator&quot;&gt;Simple use: Animated progress indicator&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#simple-use-animated-progress-indicator&quot; aria-labelledby=&quot;simple-use-animated-progress-indicator&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;At its simplest, the &lt;code&gt;animation-timeline&lt;/code&gt; property lets us link any keyframe animation to the progress of scroll. For the first demo, let’s create a festive progress indicator by sliding Santa on his sleigh from the left to the right of the screen.&lt;/p&gt;&lt;p&gt;First, we’ll create the keyframe animation. We’ll use a &lt;code&gt;calc&lt;/code&gt; function so that Santa moves to the end of the viewport but not beyond:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; slide&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100vw - 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s write some CSS to position an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element with a class of &lt;code&gt;santa&lt;/code&gt; at the bottom of the page.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100vh - 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can apply the animation to our element using &lt;code&gt;animation-timeline&lt;/code&gt;, with the scroll() function:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slide&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By default, the &lt;code&gt;scroll()&lt;/code&gt; function will link the animation to the nearest scroll container. For a progress indicator, we’d probably want to make sure our animation is linked to the &lt;code&gt;root&lt;/code&gt; scroll container so that the progress bar reflects the user’s progress through the article. We can specify this in the &lt;code&gt;scroll()&lt;/code&gt; function.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slide&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Update: link to `root` scroll container */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In addition, we can specify the &lt;code&gt;block&lt;/code&gt; or &lt;code&gt;inline&lt;/code&gt; access for our scroll animation to respond to. The default is &lt;code&gt;block&lt;/code&gt;, but if we wanted it to respond to the &lt;code&gt;inline&lt;/code&gt; axis this is how we’d do it:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slide&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Optional: switch to `inline` axis */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root inline&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we scroll the page, we should see Santa slide from left to right as we go. &lt;/p&gt;&lt;p&gt;But right now, the animation doesn’t exactly match the rate of scrolling: at some points, it’s faster than others. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;The default value for &lt;code&gt;animation-timing-function&lt;/code&gt; is &lt;code&gt;ease&lt;/code&gt;, meaning animations will start slowly, speed up in the middle, and slow down towards the end. &lt;/p&gt;&lt;p&gt;We can set a value of &lt;code&gt;linear&lt;/code&gt; to ensure the progress of our animation matches the progress of scroll.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slide&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Added timing function */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timing-function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can simplify this with the &lt;code&gt;animation&lt;/code&gt; shorthand.&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;Take care to ensure declaring &lt;code&gt;animation-timeline&lt;/code&gt; &lt;strong&gt;after&lt;/strong&gt; the shorthand. Although this property is not included in the shorthand, it &lt;strong&gt;is&lt;/strong&gt; overridden by the shorthand.&lt;/p&gt;&lt;/aside&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Update to use `animation` shorthand */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slide linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;JjxBzvO&quot; data-user=&quot;michellebarker&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/michellebarker/pen/JjxBzvO&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;parallax-images&quot;&gt;Parallax images&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#parallax-images&quot; aria-labelledby=&quot;parallax-images&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;How about something a little more exciting than a progress bar? &lt;/p&gt;&lt;p&gt;We can use exactly the same technique to add a parallax effect to a web page. This keyframe animation translates an element on the &lt;code&gt;y-axis&lt;/code&gt;. We can use a custom property (&lt;code&gt;--translate&lt;/code&gt;) to make it easy to adjust the amount our image moves.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; parallax&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * -1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we will use the &lt;code&gt;prefers-reduced-motion&lt;/code&gt; media query to ensure that users who have indicated a preference for reduced motion at the system level will see the regular static images.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Position &amp;lt;img&gt; element */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.recessed-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Animation styles only applied for users with no preference for reduced motion */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.recessed-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; parallax linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can see the parallax effect in action in the demo. As we scroll the page, the hero image appears to move at a slower rate than the text content, giving it a three-dimensional feel. As a bonus, we’re also applying a parallax effect to the other images in the article, by translating them in the opposite direction.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;RwvLPPN&quot; data-user=&quot;michellebarker&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/michellebarker/pen/RwvLPPN&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;multi-layer-parallax&quot;&gt;Multi-layer parallax&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#multi-layer-parallax&quot; aria-labelledby=&quot;multi-layer-parallax&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We can extend this parallax effect further and create multi-layered backgrounds that respond to scroll! &lt;/p&gt;&lt;p&gt;Let&amp;#39;s position three elements on top of each other at the top of our page.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Setting a minimum height ensures our page is scrollable! */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 300vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Position the three backgrounds */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.background,&lt;br /&gt;.mid,&lt;br /&gt;.foreground&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We’ll set a custom property for each one. We want the elements in the foreground to move the most and the ones in the background to move the least, so we’ll give the foreground element the highest value and the background the lowest:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.background&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.mid&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 250px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.foreground&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 500px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, we can apply the animation to our elements like in the previous example.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.background,&lt;br /&gt;  .mid,&lt;br /&gt;  .foreground&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; parallax linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; parallax&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * -1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The custom properties ensure each layer moves at a different rate, giving our page the illusion of depth.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;gOqKyNW&quot; data-user=&quot;michellebarker&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/michellebarker/pen/gOqKyNW&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;non-ancestor-scroll-containers&quot;&gt;Non-ancestor scroll containers&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#non-ancestor-scroll-containers&quot; aria-labelledby=&quot;non-ancestor-scroll-containers&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If we want to link an animation to the scroll progress of a non-ancestor element, we’ll need a couple of new properties:&lt;/p&gt;&lt;p&gt;&lt;code&gt;scroll-timeline&lt;/code&gt; (shorthand for &lt;code&gt;scroll-timeline-name&lt;/code&gt; and &lt;code&gt;scroll-timeline-axis&lt;/code&gt;) is defined on the scroll container. Here, we specify a timeline name using custom property syntax and the &lt;code&gt;inline&lt;/code&gt; or &lt;code&gt;block&lt;/code&gt; axis (the default is &lt;code&gt;block&lt;/code&gt;).&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.scroll-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scroll&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --progress block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s adjust the example in the previous demo so that the parallax background animation is tied to the progress of a fixed scroll container, which is &lt;strong&gt;not&lt;/strong&gt; an ancestor of the elements we’re animating. Instead of using the &lt;code&gt;scroll()&lt;/code&gt; function for &lt;code&gt;animation-timeline&lt;/code&gt;, we need to use the name of our timeline:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.background,&lt;br /&gt;.mid,&lt;br /&gt;.foreground&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; parallax linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --progress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, we must set the &lt;code&gt;timeline-scope&lt;/code&gt; property on a &lt;strong&gt;common ancestor&lt;/strong&gt; of our scroll container and the elements we’re animating. In this case, we can use the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;timeline-scope&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --progress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, scrolling the fixed scroll container triggers the animation.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;LYqrKNe&quot; data-user=&quot;michellebarker&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/michellebarker/pen/LYqrKNe&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;browser-support&quot;&gt;Browser support&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#browser-support&quot; aria-labelledby=&quot;browser-support&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Scroll-driven animations are currently only supported in Chromium, so you’ll need to ensure you provide fallbacks for users whose browsers don’t yet support them. Consider using feature queries to only deliver animation-dependent styles to supporting browsers:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;.recessed-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--translate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; parallax linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scroll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;view-progress-timelines&quot;&gt;View progress timelines&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#view-progress-timelines&quot; aria-labelledby=&quot;view-progress-timelines&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Also, as part of the Scroll-driven Animations specification, view progress timelines enable us to link an animation to the progress of an element through the scrollport. This means we can trigger animations when elements enter and exit the viewport.&lt;/p&gt;&lt;p&gt;In the case of our second demo, where we’re animating images throughout the page, it might be more desirable to link the animations to the progress through the viewport rather than the scroll position of the entire page.&lt;/p&gt;&lt;p&gt;To create an anonymous view progress timeline, we can simply use the &lt;code&gt;view()&lt;/code&gt; function in place of the &lt;code&gt;scroll()&lt;/code&gt; function:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.some-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; appear linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; appear&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;0%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;QWYmQPN&quot; data-user=&quot;michellebarker&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/michellebarker/pen/QWYmQPN&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;We can also specify an &lt;code&gt;animation-range&lt;/code&gt; to control when the animation should start and end in relation to its position in the scrollport. &lt;/p&gt;&lt;p&gt;For example, if we want to specify that an element should begin its animation as soon as it begins to enter the viewport and complete the animation once the entire element is in view, we can declare the animation range like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; appear linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; entry 0% entry 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As with scroll progress timelines, it’s also possible to create a named view progress timeline using the &lt;code&gt;view-timeline&lt;/code&gt; property.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scroll-driven-animations/#resources&quot; aria-labelledby=&quot;resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Discover more about scroll-driven animations!&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/scroll-animations-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Scroll-driven Animations specification&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nFbuXdEU-oA&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bramus CSS Day talk (video)&lt;/a&gt; by Bramus Van Damme&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/articles/scroll-driven-animations/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Introduction to scroll-driven animations&lt;/a&gt; by Bramus Van Damme&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/blog/scroll-progress-animations-in-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Scroll progress animations in CSS&lt;/a&gt; by Michelle Barker&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://css-irl.info/&quot;&gt;Michelle Barker&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/566737ad-94da-426c-9995-bb7e4c0d4599_michelle.jpg?auto=compress,format&amp;rect=0,135,533,533&amp;w=150&amp;h=150&quot; alt=&quot;Michelle Barker&quot; /&gt;
  &lt;p&gt;Senior Front End Developer at Ada Mode and CSS cheerleader&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Michelle selected &lt;strong&gt;&lt;a href=&quot;https://www.unicef.org.uk/&quot;&gt;Unicef UK&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.unicef.org.uk/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://www.unicef.org.uk/wp-content/uploads/2022/10/unicef-uk-logo-square.png&quot; alt=&quot;Unicef UK&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The UK Committee for UNICEF (UNICEF UK) raises funds for UNICEF’s emergency and development work for children. We also promote and protect children’s rights in the UK and internationally. We are a UK charity, entirely funded by supporters.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS Nesting</title>
    <link href="https://12daysofweb.dev/2023/css-nesting/"/>
    <updated>2023-12-20T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/css-nesting/</id>
    <content type="html">



&lt;p&gt;CSS Nesting is a new syntax for CSS that lets you nest selectors inside of other selectors, where every nested selector is relative to their parent. &lt;/p&gt;&lt;p&gt;In its simplest form, it looks like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Jolly&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A browser will take the style for an element with the class &lt;code&gt;card-title&lt;/code&gt; and apply it only if that element is nested inside an element with the class &lt;code&gt;card&lt;/code&gt;. In other words, a browser will interpret it like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card .card-title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Jolly&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;benefits-of-native-css-nesting&quot;&gt;Benefits of Native CSS Nesting&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#benefits-of-native-css-nesting&quot; aria-labelledby=&quot;benefits-of-native-css-nesting&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now some relevant implementation details complicate things that we&amp;#39;ll get to later (this is the web, after all!), but this example is enough to go over the benefits that CSS nesting brings:&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;less-typing&quot;&gt;Less typing&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#less-typing&quot; aria-labelledby=&quot;less-typing&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In the &amp;quot;interpreted&amp;quot; version above, you can see that the browser duplicated &lt;code&gt;.card&lt;/code&gt; for us, but in our source, we only had to write it once. By nesting selectors, you no longer have to repeat a part of your selector if you want to prevent your styles from applying too broadly. In addition, less typing also means your files end up being smaller, and, therefore faster to download.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;easier-scoping&quot;&gt;Easier scoping&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#easier-scoping&quot; aria-labelledby=&quot;easier-scoping&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;That also means that it&amp;#39;s easier to scope. If you&amp;#39;re working on a card, you only have to write that &lt;code&gt;.card&lt;/code&gt; selector once and nest all the relevant CSS inside it. That means you&amp;#39;ll need to write less specific selectors since they&amp;#39;re already scoped to their parent. This also makes your code much more portable, as you don&amp;#39;t have to go through your CSS to find all the styles that apply to the card but can take &lt;code&gt;.card&lt;/code&gt; and everything in it instead.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;your-css-follows-the-dom&quot;&gt;Your CSS follows the DOM&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#your-css-follows-the-dom&quot; aria-labelledby=&quot;your-css-follows-the-dom&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A benefit of this is that your CSS starts to mimic your DOM. In the above example, &lt;code&gt;card-title&lt;/code&gt; is nested both in the CSS as well as in the DOM. When your CSS mimics your DOM, it&amp;#39;s much easier to reason about, and easier to understand what effects your changes will have.  If you&amp;#39;ve ever worked on a large CSS codebase, you know how dangerous deleting CSS can be even if you think you no longer use it. &lt;/p&gt;&lt;p&gt;When your CSS follows your HTML structure, you&amp;#39;re able to delete things with much more confidence. For example, when you remove the &lt;code&gt;card-footer&lt;/code&gt; from your card HTML, you know that your &lt;code&gt;.card-footer&lt;/code&gt; CSS can only apply to that part of your site, so you can remove it from the CSS as well.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;nesting-complexities&quot;&gt;Nesting Complexities&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#nesting-complexities&quot; aria-labelledby=&quot;nesting-complexities&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now that you know what makes CSS Nesting so useful, let&amp;#39;s explore some of the complexities.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;versions&quot;&gt;Versions&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#versions&quot; aria-labelledby=&quot;versions&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;At this point, we need to point out that there are currently two versions of CSS nesting: the strict version, which is what Chromium up to 119 and Safari up to 17.1 implement, and the &amp;quot;relaxed&amp;quot; version, which is what Firefox shipped with and is now available in Safari 17.2 and Chromium 120. &lt;/p&gt;&lt;p&gt;The difference between them lies in how they deal with nesting element selectors (like &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;div&lt;/code&gt;). The strict version allows for any selector that begins with a non-letter to be nested without the &amp;quot;nesting selector&amp;quot;, the &lt;code&gt;&amp;amp;&lt;/code&gt;. That means that instead of this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Jolly&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You have to write this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Jolly&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or your &lt;code&gt;h3&lt;/code&gt; style won&amp;#39;t be applied. The reason for this is that properties (like &lt;code&gt;margin&lt;/code&gt;) also start with a letter so the browser&amp;#39;s CSS engine wouldn&amp;#39;t know if you were adding a new property or a new nesting selector. &lt;/p&gt;&lt;p&gt;Browsers found a way around that, so the relaxed version allows you to nest element selectors without the &lt;code&gt;&amp;amp;&lt;/code&gt;, making everything a lot simpler. By the time you read this article, Chromium 120 and Safari 17.2 will have been released, so all browsers now support the relaxed version.&lt;/p&gt;&lt;p&gt;I would suggest you keep using the strict version, though, since that will keep working across all browsers.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-nesting-selector-and-how-nesting-gets-resolved-by-the-browser&quot;&gt;The nesting selector and how nesting gets resolved by the browser&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#the-nesting-selector-and-how-nesting-gets-resolved-by-the-browser&quot; aria-labelledby=&quot;the-nesting-selector-and-how-nesting-gets-resolved-by-the-browser&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;So, does that mean you don&amp;#39;t &lt;em&gt;need&lt;/em&gt; the nesting selector anymore? For simple nesting no. But the nesting selector lets you control how nesting should happen. To understand how it does that, you need to know three things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If a nested selector doesn&amp;#39;t have an &lt;code&gt;&amp;amp;&lt;/code&gt;, it gets one added to the front of it (with a space) implicitly&lt;/li&gt;&lt;li&gt;The &amp;quot;&amp;amp;&amp;quot; is replaced with &amp;quot;is(&amp;lt;parent selector&amp;gt;)&amp;quot; in the CSS engine.&lt;/li&gt;&lt;li&gt;You can add an &amp;amp; anywhere in the selector (including multiple times)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Let&amp;#39;s go over these in order.&lt;/p&gt;&lt;h4&gt;Implicit Nesting selector&lt;/h4&gt;&lt;p&gt;Going back to our first example, the nested &lt;code&gt;.card-title&lt;/code&gt; doesn&amp;#39;t have a nesting selector, so the browser will add one implicitly:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;(implicit &#39;&amp;amp;&#39;) .card-title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Jolly&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On its own, this doesn&amp;#39;t matter a lot, but it&amp;#39;s important to keep in mind when you know that the &lt;code&gt;&amp;amp;&lt;/code&gt; gets replaced.&lt;/p&gt;&lt;h4&gt;Resolved selector&lt;/h4&gt;&lt;p&gt;The &lt;code&gt;&amp;amp;&lt;/code&gt; gets replaced with &amp;quot;is(&amp;lt;parent selector&amp;gt;)&amp;quot; so the nested selector in the code above ends up not being &lt;code&gt;.card .card-title&lt;/code&gt; as we said at the beginning of this article, but as &lt;code&gt;:is(.card) .card-title&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;In this example, that doesn&amp;#39;t matter a lot because both of them have &lt;a href=&quot;https://polypane.app/css-specificity-calculator/#selector=.card%20.card-title%2C%20%3Ais(.card)%20.card-title&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the same specificity (0,2,0)&lt;/a&gt;, but if you have comma separated selector as a parent, you could accidentally be making a rule with a very high specificity:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card,&lt;br /&gt;#xmas-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This gets resolved to this: &lt;code&gt;:is(.card, #xmas-card) .card-title&lt;/code&gt; which &lt;a href=&quot;https://polypane.app/css-specificity-calculator/#selector=%3Ais(.card%2C%20%23xmas-card)%20.card-title&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;has a specificity of (1,1,0)&lt;/a&gt;, because the &lt;code&gt;:is()&lt;/code&gt; pseudo selector will get the specificity of the most specific item, in this case, the &lt;code&gt;id&lt;/code&gt;. And that&amp;#39;s also the case if your &lt;code&gt;.card-title&lt;/code&gt; isn&amp;#39;t in the &lt;code&gt;#xmas-card&lt;/code&gt; at all but in a regular &lt;code&gt;.card.&lt;/code&gt;&lt;/p&gt;&lt;p&gt;This can get even trickier if you realize that the &lt;code&gt;:is()&lt;/code&gt; selectors also get nested. Let&amp;#39;s go over how this works with the following three-levels-deep nesting:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;First, the &amp;quot;p&amp;quot; is implicit &lt;code&gt;&amp;amp; p&lt;/code&gt;. &lt;/li&gt;&lt;li&gt;That gets replaced with the parent, which for convenience, we&amp;#39;ll also add the &lt;code&gt;&amp;amp;&lt;/code&gt; to, creating &lt;code&gt;:is(&amp;amp; .card-body) p&lt;/code&gt;. &lt;/li&gt;&lt;li&gt;Then lastly, we also fill in the &amp;quot;&amp;amp;&amp;quot; there, replacing it with &lt;code&gt;:is(.card)&lt;/code&gt; resulting in &lt;code&gt;:is(:is(.card) .card-body) p&lt;/code&gt; which is what your browser ends up using.&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;Adding an &amp;amp; selector&lt;/h4&gt;&lt;p&gt;You can be explicit in how you nest by adding the &lt;code&gt;&amp;amp;&lt;/code&gt; selector. I personally think this is more readable, but beyond that, it can also affect how your nesting works. That&amp;#39;s because the space is also a type of selector: the descendant selector. And so, whether or not you add a space after your &lt;code&gt;&amp;amp;&lt;/code&gt; can make a difference. &lt;/p&gt;&lt;p&gt;The following code will apply when you hover the card:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is because it resolves to &lt;code&gt;:is(.card):hover&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The following code will do something different:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; :hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because of the space, the &lt;code&gt;:hover&lt;/code&gt; part is now targeting descendants of cards and so acts like &lt;code&gt;:is(.card) *:hover&lt;/code&gt;. Pseudo-classes like &lt;code&gt;:hover&lt;/code&gt; get an implicit &lt;code&gt;*&lt;/code&gt; (universal element selector) before them. So keep that space in mind.&lt;/p&gt;&lt;p&gt;By adding an explicit &lt;code&gt;&amp;amp;&lt;/code&gt; selector somewhere else in the selector, you can target different parts of your nesting. For example, to style cards but only if they&amp;#39;re in a list, you could do this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.list&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The downside is that all the styling of your card components would also have &lt;code&gt;.list&lt;/code&gt; as a parent selector, making it more specific and less modular. &lt;/p&gt;&lt;p&gt;Instead, you could write this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token selector&quot;&gt;.list &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This way, all your other card styling could be scoped to the card, and the extra styling when your card is in a list would be included with it, keeping everything nice and modular.&lt;/p&gt;&lt;p&gt;Adding multiple selectors is useful if you want to style elements in a sequence. For example, to add &lt;code&gt;margin&lt;/code&gt; to each card except the first when they&amp;#39;re in a list:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.list &amp;amp; + &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This resolves to &lt;code&gt;.list :is(.card) + :is(.card)&lt;/code&gt;, or written more simply, &lt;code&gt;.list .card + .card&lt;/code&gt;. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;nesting-at-rules&quot;&gt;Nesting At-rules&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#nesting-at-rules&quot; aria-labelledby=&quot;nesting-at-rules&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A very useful part of CSS Nesting is that you can also nest at-rules like &lt;code&gt;@media&lt;/code&gt;, &lt;code&gt;@supports,&lt;/code&gt; and friends. &lt;/p&gt;&lt;p&gt;Instead of writing this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40rem&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can nest that media query:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40rem&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice how we don’t have to repeat &lt;code&gt;.card&lt;/code&gt; and that we can use the CSS declarations directly in the media query because the browser implicitly reads it as this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40rem&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And as we learned previously, that &lt;code&gt;&amp;amp;&lt;/code&gt; is then replaced with &lt;code&gt;:is(.card)&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;things-to-watch-out-for-when-nesting&quot;&gt;Things to watch out for when nesting&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#things-to-watch-out-for-when-nesting&quot; aria-labelledby=&quot;things-to-watch-out-for-when-nesting&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Back when I first used Sass, I went wild with nesting, sometimes nesting 20 levels deep. It’s very tempting just to keep going as you build out your styling. But each nesting level also increases the specificity of your selector, making it harder to edit later (not to mention the indenting!).&lt;/p&gt;&lt;p&gt;A simple rule of thumb is to see if you can break out into a new set of nesting when you reach 3 or 4 levels deep. This makes your selectors easy to reason about, and there is probably a logical break for your component and its sub-components. There are multiple other strategies to deal with this, such as keeping empty parent selectors and splitting between layout and style. I explore these strategies in &lt;a href=&quot;https://kilianvalkhof.com/2021/css-html/css-nesting-specificity-and-you/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Nesting, specificity and you&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Another tricky part is that because nesting gets resolved to un-nested code, the order you write CSS in might not be the order your CSS gets applied. I wrote about this in “&lt;a href=&quot;https://kilianvalkhof.com/2023/css-html/the-gotchas-of-css-nesting/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The gotchas of CSS Nesting&lt;/a&gt;”. The short of it is: You can nest at-rules before applying regular properties, like so:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; all&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you follow your CSS order, the background would be &lt;code&gt;blue&lt;/code&gt;, because at-rules add no specificity and &lt;code&gt;background: blue&lt;/code&gt; comes last.&lt;/p&gt;&lt;p&gt;Once the browser finishes computing CSS values, it ends up applying the rules like this and moving the media query last:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; all&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;	&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:is(body)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now &lt;code&gt;background: red&lt;/code&gt; is last, which ends up being the applied background color. &lt;/p&gt;&lt;p&gt;The best way to deal with this, and to keep your code easy to reason about is to only nest &lt;code&gt;after&lt;/code&gt; all the regular properties and not to mingle them even though it&amp;#39;s allowed by the nesting syntax.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;thats-css-nesting&quot;&gt;That’s CSS Nesting&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-nesting/#thats-css-nesting&quot; aria-labelledby=&quot;thats-css-nesting&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://caniuse.com/css-nesting&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nesting is available in all browsers&lt;/a&gt;, though you’ll want to keep using the strict notation to keep the widest compatibility. &lt;/p&gt;&lt;p&gt;Nesting helps you keep your CSS smaller, easier to reason about, and more closely follow the DOM that you’re styling. When using Nesting, try not to nest too deeply, and keep in mind that your CSS needs to be resolved, which can change both the order and the selectors your browser ends up using.&lt;/p&gt;&lt;p&gt;If you want to learn more about nesting, here are some additional resources:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://caniuse.com/css-nesting&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CanIUse support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN on nesting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/css-nesting-relaxed-syntax-update/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Relaxed nesting announcement&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The latest &lt;a href=&quot;https://www.w3.org/TR/css-nesting-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS nesting spec&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kilianvalkhof.com/2023/css-html/the-gotchas-of-css-nesting/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The gotchas of CSS Nesting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kilianvalkhof.com/2021/css-html/css-nesting-specificity-and-you/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Nesting, specificity and you&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://kilianvalkhof.com/&quot;&gt;Kilian Valkhof&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/e01991d2-1826-48b5-90e5-8429a0b0c191_kilian.jpg?auto=compress,format&amp;rect=0,0,512,512&amp;w=150&amp;h=150&quot; alt=&quot;Kilian Valkhof&quot; /&gt;
  &lt;p&gt;Kilian is a web developer from the netherlands, building Polypane.app, the browser for developers.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Kilian selected &lt;strong&gt;&lt;a href=&quot;https://www.givingwhatwecan.org/&quot;&gt;Giving Green Fund&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.givingwhatwecan.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://cdn.sanity.io/images/4rsg7ofo/production/eb68062c2664d44072541adadb3aa1ff52f0003b-500x500.png?w=3840&amp;q=75&amp;fit=clip&amp;auto=format&quot; alt=&quot;Giving Green Fund&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The climate crisis sits at the heart of many problems around the world, increasing inequality and disproportionately affecting those least responsible for it. If we want to keep earth livable for our children, we need to fight it at many fronts. Giving Green is a fund that research projects and funds those most effective.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>View Transitions</title>
    <link href="https://12daysofweb.dev/2023/view-transitions/"/>
    <updated>2023-12-19T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/view-transitions/</id>
    <content type="html">



&lt;p&gt;Web applications these days are becoming more complex thus, having smooth transitions between view states as a form of&lt;a href=&quot;https://www.smashingmagazine.com/2017/01/how-functional-animation-helps-improve-user-experience/#what-is-functional-animation&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; functional animation&lt;/a&gt; has the practical benefit of reducing cognitive load, preventing change blindness, and establishing better recall in spatial relationships.&lt;/p&gt;&lt;p&gt;Trying to animate between different DOM states used to involve a serious amount of Javascript and CSS because of the number of factors we had to take care of. In addition to the animations themselves, we also had to worry about handling the loading and rendering of content within the different states and potential accessibility issues.&lt;/p&gt;&lt;p&gt;The View Transitions API was &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/6464&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;proposed&lt;/a&gt; in the CSS working group back in 2021 to allow transition animations when navigating between different application views. A lot of work has gone into this, and&lt;a href=&quot;https://www.w3.org/TR/css-view-transitions-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; the specification&lt;/a&gt; is now at Candidate Recommendation status.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/view-transitions/#how-does-it-work&quot; aria-labelledby=&quot;how-does-it-work&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Generally, if we want to animate something smoothly, it must have a start state and an end state, then we have to figure out how to fill in the gap between the two states in a gradual manner. As an oversimplification, CSS transitions and animations today generally work because the browser can compute the values of the in-between states of an element.&lt;/p&gt;&lt;p&gt;If we want multiple DOM nodes to participate in the same animation, things become very tricky because the computation required increases significantly. The proposed solution is to handle the complicated in-between state in a separate layer altogether with the help of pseudo-elements.&lt;/p&gt;&lt;p&gt;The visual transition is done using a static visual capture of the original state and a live capture of the new state, represented as &lt;a href=&quot;https://drafts.csswg.org/css-view-transitions/#view-transition-pseudos&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a tree of pseudo-elements&lt;/a&gt;.&lt;/p&gt;&lt;pre&gt;::view-transition
├─ ::view-transition-group(name)
│  └─ ::view-transition-image-pair(name)
│     ├─ ::view-transition-old(name)
│     └─ ::view-transition-new(name)
└─ …other groups…&lt;/pre&gt;&lt;p&gt;It all starts with the &lt;code&gt;startViewTransition()&lt;/code&gt; method, which returns a&lt;a href=&quot;https://drafts.csswg.org/css-view-transitions/#viewtransition&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; ViewTransition&lt;/a&gt; object when called. The state at this point is captured as the “old” state, and rendering is paused.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;startViewTransition()&lt;/code&gt; takes a callback function as an argument, called asynchronously once the old state has been captured. Once the promise is fulfilled, the new state of the document is captured as the “new” state, and now we have the two states necessary for a smooth transition to happen.&lt;/p&gt;&lt;p&gt;What’s particularly interesting about how this feature is implemented is that “a failure to create a visual transition, which can happen due to misconfiguration or device constraints, will not prevent the developer’s &lt;code&gt;UpdateCallback&lt;/code&gt; being called.”&lt;/p&gt;&lt;p&gt;As previously mentioned, the &lt;code&gt;startViewTransition()&lt;/code&gt; method takes a callback function as an argument, and this function will always be called even if the animation does not happen due to reasons. I think the idea is pretty smart, and I highly suggest reading the specification because it’s a very readable explanation of the details.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;view-transition-api-in-action&quot;&gt;View Transition API in action&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/view-transitions/#view-transition-api-in-action&quot; aria-labelledby=&quot;view-transition-api-in-action&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;These days, a common pattern we see on the web is data that gets populated after the page has loaded. It could be a user interaction that triggers a change in the content with new content that hadn’t existed in the DOM previously. We can animate such a content change using the View Transitions API.&lt;/p&gt;&lt;p&gt;For our example, we&amp;#39;ll build an image gallery and have a scenario where clicking on a thumbnail will populate the main display with a larger version of the image.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/657c6bda531ac2845a269065_view-transitions-gallery.jpeg?auto=format,compress&quot; alt=&quot;A preview of the image gallery where a large area on the left is displaying a title slide for &amp;#39;fluffy Philharmonic&amp;#39; and on the right is a vertical stack of four images of cute illustrated animals playing string instruments.&quot; /&gt;&lt;/p&gt;&lt;p&gt;The basic markup for the display looks something like this:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;main-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://i.imgur.com/j6tUehw.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Mamamoo World Tour MYCON&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figcaption&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-heading&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our list of thumbnails looks like this:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;thumbnails&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;thumbnail&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Solar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- additional list items --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s start off with our callback function (to be passed to the &lt;code&gt;startViewTransition()&lt;/code&gt; method):&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mainImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;figure img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;displayNewImage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  mainImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because this is just a demo, this function sets the main image source to the thumbnail that was clicked. In an ideal situation, we would have wanted to have optimized different images because of performance but let’s live with this for now.&lt;/p&gt;&lt;p&gt;As not every browser currently supports the View Transitions API, we need to include a check for support. The code for the checking View Transition support looks like this:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;startViewTransition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;displayNewImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startViewTransition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;displayNewImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The default &lt;code&gt;ViewTransition&lt;/code&gt; is a cross-fade effect, where the old view animates from &lt;code&gt;opacity: 1&lt;/code&gt; to &lt;code&gt;opacity: 0&lt;/code&gt;, and the new view animates from &lt;code&gt;opacity: 0&lt;/code&gt; to &lt;code&gt;opacity: 1&lt;/code&gt;. The browser does this out-of-the-box as the default animation. If this effect is sufficient, no additional CSS is necessary.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;js,result&quot; data-slug-hash=&quot;rNPPmww&quot; data-user=&quot;huijing&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/huijing/pen/rNPPmww&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;The entire page is involved in the transition for this most basic implementation. But we can also target specific elements to be animated separately from the rest of the page by assigning a &lt;code&gt;view-transition-name&lt;/code&gt; to the element.&lt;/p&gt;&lt;p&gt;We can try something more than a simple cross-fade. Let’s make it seem like the image is growing out from each respective thumbnail when the thumbnail is clicked on with the help of some additional CSS on the view transition pseudo-elements.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::view-transition-old(main-image),&lt;br /&gt;::view-transition-new(main-image)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform-origin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100% &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--originY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;::view-transition-new(main-image)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400ms ease-out both grow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;figure&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-transition-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; main-image&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; grow&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We need to update the markup and Javascript a little update the &lt;code&gt;transform-origin&lt;/code&gt; property value when the thumbnails are clicked. Let’s add a &lt;code&gt;data-index&lt;/code&gt; attribute to each thumbnail, which can be used to calculate the updated value so the main display image starts animating from the position of each thumbnail.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;thumbnails&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;thumbnail&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Solar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-index&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- additional list items --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And update the Javascript to modify the &lt;code&gt;--originY&lt;/code&gt; custom property value that controls the transform-origin of the scale transformation along the &lt;code&gt;y-axis&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;displayNewImage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  mainImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;--originY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12.5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The end result of all that looks like this:&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;wvNNdpB&quot; data-user=&quot;huijing&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/huijing/pen/wvNNdpB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;We can target other elements to be animated separately by giving them their own &lt;code&gt;view-transition-name&lt;/code&gt; value. The &lt;code&gt;view-transition-name&lt;/code&gt; can be anything at all, but it needs to be unique and cannot be &lt;code&gt;none&lt;/code&gt;, as that would result in no transition at all.&lt;/p&gt;&lt;p&gt;Maybe we want an image header to go with the main display. Again, for demo purposes, I’m just going to use the &lt;code&gt;alt&lt;/code&gt; text from the thumbnail, but the content could come from somewhere else. The point is the content is changing. Let’s update the &lt;code&gt;displayNewImage&lt;/code&gt; callback:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;displayNewImage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  mainImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  imageHeading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;--originY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    clickTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12.5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The animation is currently on the &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; element, which contains the &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; element where the text is displayed, so the scale effect will include the &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;. But the View Transitions API allows us to separate the &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; animation from the &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;, and to me, that’s a huge plus.&lt;/p&gt;&lt;p&gt;Once a &lt;code&gt;view-transition-name&lt;/code&gt; is assigned to the &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;, it will now cross-fade when the &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; scales. You can also customize the animation for the &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; with CSS. There are so many possibilities!&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;abRgNEb&quot; data-user=&quot;huijing&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/huijing/pen/abRgNEb&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;can-we-use-it-today&quot;&gt;Can we use it today?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/view-transitions/#can-we-use-it-today&quot; aria-labelledby=&quot;can-we-use-it-today&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As it was put forth by the folks at Google, Chromium has had a working implementation of the View Transitions API since version 111. Both Firefox and Webkit are currently working on their implementation of this feature, tracked in&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1823896&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Bug 1823896&lt;/a&gt; on Firefox Bugzilla and&lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=259055&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; Bug 259055&lt;/a&gt; on Webkit Bugzilla, respectively.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/view-transitions/#wrapping-up&quot; aria-labelledby=&quot;wrapping-up&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Hopefully, this post manages to highlight the potential of View Transitions and inspires you to explore more and give it a try yourself.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/view-transitions/#references&quot; aria-labelledby=&quot;references&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-view-transitions&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS View Transitions Module Level 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/web-platform/view-transitions/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Smooth and simple transitions with the View Transitions API&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://chenhuijing.com/&quot;&gt;Chen Hui Jing&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/65772fb1531ac2845a25e99c_chen-hui-jing.jpg?auto=format%2Ccompress&amp;rect=0%2C2%2C958%2C958&amp;w=150&amp;h=150&quot; alt=&quot;Chen Hui Jing&quot; /&gt;
  &lt;p&gt;Chen Hui Jing is a self-taught designer and developer living in Singapore, who loves CSS more than most people. She can be found spanning routes in some local climbing gym.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Chen selected &lt;strong&gt;&lt;a href=&quot;https://redpandanetwork.org/&quot;&gt;Red Panda Network&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://redpandanetwork.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://redpandanetwork.org/images/logo.png&quot; alt=&quot;Red Panda Network&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Red Panda Network is committed to the conservation of wild red pandas and their habitat through the education and empowerment of local communities.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>New JS Array Methods</title>
    <link href="https://12daysofweb.dev/2023/new-js-array-methods/"/>
    <updated>2023-12-18T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/new-js-array-methods/</id>
    <content type="html">



&lt;p&gt;Let’s learn what these Array methods do and how they work!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-reversed-copy-with-the-arrayprototypetoreversed-method&quot;&gt;Creating a reversed copy with the Array.prototype.toReversed() method&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#creating-a-reversed-copy-with-the-arrayprototypetoreversed-method&quot; aria-labelledby=&quot;creating-a-reversed-copy-with-the-arrayprototypetoreversed-method&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s say you have an array of wizards.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Merlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ursula&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Gandalf&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.reverse()&lt;/code&gt; method modifies the original array.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&quot;Gandalf&quot;, &quot;Ursula&quot;, &quot;Merlin&quot;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Historically, if you wanted to create a reversed &lt;em&gt;copy&lt;/em&gt; of the array instead of modifying the original, you would have to clone it first, &lt;em&gt;then&lt;/em&gt; reverse it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; reverseWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&quot;Gandalf&quot;, &quot;Ursula&quot;, &quot;Merlin&quot;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reverseWizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&quot;Merlin&quot;, &quot;Ursula&quot;, &quot;Gandalf&quot;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The new &lt;code&gt;Array.prototype.toReversed()&lt;/code&gt; method simplifies that into a single step.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; reverseWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toReversed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&quot;Gandalf&quot;, &quot;Ursula&quot;, &quot;Merlin&quot;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reverseWizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&quot;Merlin&quot;, &quot;Ursula&quot;, &quot;Gandalf&quot;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/rNomxaW?editors=0011&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here&amp;#39;s a demo of the Array.prototype.toReversed() method.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-spliced-copy-of-an-array-with-the-arrayprototypetospliced-method&quot;&gt;Creating a spliced copy of an array with the Array.prototype.toSpliced() method&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#creating-a-spliced-copy-of-an-array-with-the-arrayprototypetospliced-method&quot; aria-labelledby=&quot;creating-a-spliced-copy-of-an-array-with-the-arrayprototypetospliced-method&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.splice()&lt;/code&gt; method is used to add, remove, and replace items in an array. &lt;/p&gt;&lt;p&gt;When using the method, the original array is modified.&lt;/p&gt;&lt;p&gt;The first argument is the index of the item you want to modify in the array and is the only required argument. The second argument is the number of items to delete from the array. It can be a number from &lt;code&gt;0&lt;/code&gt; through the length of the array.&lt;/p&gt;&lt;p&gt;If you omit the second argument, the &lt;code&gt;Array.prototype.splice()&lt;/code&gt; method will delete every item in the array from the start index on.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Merlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ursula&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Gandalf&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Radagast&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// This removes 1 item at index 2: &quot;Gandalf&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// wizards is now [&quot;Merlin&quot;, &quot;Ursula&quot;, &quot;Radagast&quot;]&lt;/span&gt;&lt;br /&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Historically, if you want to keep the original array intact, you would clone it first, then &lt;code&gt;splice()&lt;/code&gt; it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; fewerWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The new &lt;code&gt;Array.prototype.toSpliced()&lt;/code&gt; does the same thing as &lt;code&gt;Array.prototype.splice()&lt;/code&gt; but creates a copy instead of modifying the original array.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Merlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ursula&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Gandalf&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Radagast&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lessWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSpliced&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Gandalf&#39;, &#39;Radagast&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Radagast&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lessWizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/BavRwyj?editors=0011&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here&amp;#39;s a demo of the Array.prototype.toSpliced() method.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-sorted-copy-of-an-array-with-the-arrayprototypetosorted-method&quot;&gt;Creating a sorted copy of an array with the Array.prototype.toSorted() method&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#creating-a-sorted-copy-of-an-array-with-the-arrayprototypetosorted-method&quot; aria-labelledby=&quot;creating-a-sorted-copy-of-an-array-with-the-arrayprototypetosorted-method&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.sort()&lt;/code&gt; method reorders the items in an array.&lt;/p&gt;&lt;p&gt;It modifies the original array and by default, will order the items alphanumerically.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Merlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ursula of the Sea&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Gandalf the Gray&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Gandalf the Gray&#39;, &#39;Merlin&#39;, &#39;Ursula of the Sea&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can optionally pass in a callback function that will modify the default sorting behavior.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.sort()&lt;/code&gt; method loops through each item and passes two items at a time as arguments into the callback function. You can compare those two items and return an integer telling &lt;code&gt;Array.sort()&lt;/code&gt; what to do with them.&lt;/p&gt;&lt;p&gt;If you return &lt;code&gt;-1&lt;/code&gt;, it will place the first item before the second one. If you return &lt;code&gt;1&lt;/code&gt;, it will move the second item before the current one. If you return &lt;code&gt;0&lt;/code&gt; (or nothing at all), it will leave them unchanged.&lt;/p&gt;&lt;p&gt;For example, let’s say we want to sort our &lt;code&gt;wizards&lt;/code&gt; array by the length of the wizard’s name, with the longest names first. We could do this:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;wizard1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wizard2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// If wizard1 is longer, put it before wizard2&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizard1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; wizard2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Otherwise, put wizard2 before wizard1&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Ursula of the Sea&#39;, &#39;Gandalf the Gray&#39;, &#39;Merlin&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.toSorted()&lt;/code&gt; method works exactly the same way but creates a copy of the array before sorting it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; sortedWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Gandalf&#39;, &#39;Radagast&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Gandalf the Gray&#39;, &#39;Merlin&#39;, &#39;Ursula of the Sea&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sortedWizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/RwvEQmP?editors=1011&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo of the Array.prototype.toSorted() method.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-copy-of-an-array-with-a-single-value-updated-using-the-arrayprototypewith-method&quot;&gt;Creating a copy of an array with a single value updated using the Array.prototype.with() method&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#creating-a-copy-of-an-array-with-a-single-value-updated-using-the-arrayprototypewith-method&quot; aria-labelledby=&quot;creating-a-copy-of-an-array-with-a-single-value-updated-using-the-arrayprototypewith-method&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To update a value in an array, you can use bracket notation (&lt;code&gt;[]&lt;/code&gt;), passing in the index of the value to update.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Remember, array indexes start at &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Merlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ursula&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Gandalf&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Replaces &quot;Gandalf&quot; with &quot;Radagast&quot;&lt;/span&gt;&lt;br /&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Radagast&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Radagast&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Array.prototype.with()&lt;/code&gt; method provides a simple way to copy an array and update one of its values in a single step.&lt;/p&gt;&lt;p&gt;You pass in the index to update and the value to assign to that index as arguments.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; differentWizards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wizards&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Radagast&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Gandalf&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// logs [&#39;Merlin&#39;, &#39;Ursula&#39;, &#39;Radagast&#39;]&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;differentWizards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/LYqMQwK?editors=1011&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo of the Array.prototype.with() method.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;browser-support-and-polyfills&quot;&gt;Browser support and polyfills&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#browser-support-and-polyfills&quot; aria-labelledby=&quot;browser-support-and-polyfills&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The new Array methods we looked at today are now supported in all major browsers.&lt;/p&gt;&lt;p&gt;&lt;em&gt;But&lt;/em&gt;… they’re relatively new, and not everyone updates their browsers regularly. In particular, browser updates on mobile devices are often tied to updating the entire OS. Someone running an older version of iOS, for example, won’t have support for these methods.&lt;/p&gt;&lt;p&gt;For now, I recommend using &lt;a href=&quot;https://gomakethings.com/why-i-love-polyfills/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a polyfill&lt;/a&gt; that you can remove later when browser support gets better.&lt;/p&gt;&lt;p&gt;Polyfills are functions that check if a browser supports a method or API and recreate that method using older approaches if not. Unlike a helper function, they follow the spec for the new method and are designed to be deleted as browser support improves.&lt;/p&gt;&lt;p&gt;Here are polyfills you can use for the methods we discussed in this article.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Polyfill: Array.prototype.toReversed()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toReversed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;toReversed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Polyfill: Array.prototype.toSpliced()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toSpliced&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;toSpliced&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Polyfill: Array.prototype.toSorted()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toSorted&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;toSorted&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Polyfill: Array.prototype.with()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; clone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    clone&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/#wrapping-up&quot; aria-labelledby=&quot;wrapping-up&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We covered a lot in this article, so let’s quickly wrap up what we learned.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;toReversed()&lt;/code&gt; - creates a reversed copy of an array.&lt;/li&gt;&lt;li&gt;&lt;code&gt;toSpliced()&lt;/code&gt; - creates a copy of an array and adds, removes, or replaces one or more items.&lt;/li&gt;&lt;li&gt;&lt;code&gt;toSorted()&lt;/code&gt; - creates a copy of an array and sorts the items in.&lt;/li&gt;&lt;li&gt;&lt;code&gt;with()&lt;/code&gt; - creates a copy of an array and updates a single value in the array.&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://gomakethings.com/&quot;&gt;Chris Ferdinandi&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/f9ac5856-fc58-47e3-9af7-bbe2b9247e11_chris.jpeg?auto=compress,format&amp;rect=0,0,400,400&amp;w=150&amp;h=150&quot; alt=&quot;Chris Ferdinandi&quot; /&gt;
  &lt;p&gt;Chris Ferdinandi helps people learn vanilla JavaScript and believes there’s a simpler, more resilient way to make things for the web. His &lt;a href=&quot;https://gomakethings.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;developer tips newsletter&lt;/a&gt; is read by thousands of developers each weekday. Learn more at &lt;a href=&quot;https://gomakethings.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GoMakeThings.com&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Chris selected &lt;strong&gt;&lt;a href=&quot;https://www.feedingamerica.org/&quot;&gt;Feeding America&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.feedingamerica.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-increase-contrast&quot; src=&quot;https://nvlupin.blob.core.windows.net/images/van/FAM/FAM/1/87084/images/themes/logo.svg&quot; alt=&quot;Feeding America&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Feeding America is the largest charity working to end hunger in the United States. We partner with food banks, food pantries, and local food programs to bring food to people facing hunger. We advocate for policies that create long-term solutions to hunger.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS animation-composition</title>
    <link href="https://12daysofweb.dev/2023/animation-composition/"/>
    <updated>2023-12-17T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/animation-composition/</id>
    <content type="html">



&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN&lt;/a&gt; describes &lt;code&gt;animation-composition&lt;/code&gt; as:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The &lt;code&gt;animation-composition&lt;/code&gt; CSS property specifies the composite operation to use when multiple animations affect the same property simultaneously.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Put another way, it gives us the ability to instruct animations to apply property values in ways other than the default behavior. It’s not limited to multiple animations. Animation composition affects all animated properties regardless of whether an element has one or multiple animations applied to it.&lt;/p&gt;&lt;p&gt;There are three possible values for &lt;code&gt;animation-composition&lt;/code&gt;: &lt;code&gt;replace&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, and &lt;code&gt;accumulate&lt;/code&gt;, where &lt;code&gt;replace&lt;/code&gt; is the default.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;replace&lt;/code&gt;: The effect value overrides the underlying value of the property&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt;: The effect value builds on the underlying value of the property&lt;/li&gt;&lt;li&gt;&lt;code&gt;accumulate&lt;/code&gt;: The effect and underlying values are combined&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You apply &lt;code&gt;animation-composition&lt;/code&gt; to the same element that has an animation.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.single-animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; move 2s infinite&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-composition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; accumulate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you have multiple animations, you can set &lt;code&gt;animation-composition&lt;/code&gt; for each using comma-separated values in the same order as the animations.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.multiple-animations&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; move 1s infinite&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shake 3s infinite&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; roll 2s infinite&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-composition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; add&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; accumulate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; replace&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;&lt;strong&gt;Motion warning&lt;/strong&gt;: The demos in this post will autoplay animation unless the reduce motion setting on your device is set to reduce.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#how-it-works&quot; aria-labelledby=&quot;how-it-works&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Since &lt;code&gt;replace&lt;/code&gt; is the default, its behavior is likely what you expect from animations. It’s how animations have always worked up until now. &lt;/p&gt;&lt;p&gt;For example, let’s say we have an element that we’ve moved towards the right with &lt;code&gt;transform: translateX(50px)&lt;/code&gt;. Then we apply a keyframe animation to it that translates it another &lt;code&gt;200px&lt;/code&gt; on the x-axis, &lt;code&gt;translateX(200px)&lt;/code&gt;. The element was at &lt;code&gt;50px&lt;/code&gt; and is now at &lt;code&gt;200px&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;If we change the element’s &lt;code&gt;animation-composition&lt;/code&gt; to &lt;code&gt;add&lt;/code&gt; or &lt;code&gt;accumulate&lt;/code&gt;, we change the result of the animation. The element still starts at &lt;code&gt;50px&lt;/code&gt;, but now ends up at &lt;code&gt;250px&lt;/code&gt; on the x-axis because the &lt;code&gt;200px&lt;/code&gt; is added to the initial &lt;code&gt;50px&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;YzBJmGv&quot; data-user=&quot;tylergaw&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/tylergaw/pen/YzBJmGv&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;What we’re seeing here with &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt; is basic math: 50 + 200 = 250. This is a simple example; we’ll see later that this basic math doesn’t apply to all combinations of composition and properties.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;effect-on-color&quot;&gt;Effect on color&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#effect-on-color&quot; aria-labelledby=&quot;effect-on-color&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We’re not limited to positional properties. &lt;code&gt;animation-composition&lt;/code&gt; impacts all animatable properties. And color properties produce interesting results. &lt;/p&gt;&lt;p&gt;Consider another example where we have an element with a background color of &lt;code&gt;rgb(159, 0, 10)&lt;/code&gt;. Then we apply an animation that animates the background color to &lt;code&gt;rgb(129, 255, 30)&lt;/code&gt;. The &lt;code&gt;replace&lt;/code&gt; composition does as its name says; it interpolates from the start value to the end value just as it’s declared. With &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt;, the value of each channel – in this case, &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt;, &lt;code&gt;b &lt;/code&gt;– in the starting color is added to the corresponding channel of the ending color. Because this is &lt;code&gt;rgb&lt;/code&gt;, each channel is capped at &lt;code&gt;255&lt;/code&gt;. We end up with the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;r&lt;/code&gt;: 159 + 129 = 288, so we’re capped at 255&lt;/li&gt;&lt;li&gt;&lt;code&gt;g&lt;/code&gt;: 0 + 255 = 255&lt;/li&gt;&lt;li&gt;&lt;code&gt;b&lt;/code&gt;: 10 + 30 = 40&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The ending &lt;code&gt;background-color&lt;/code&gt; for &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt; is &lt;code&gt;rgb(255, 255, 40)&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;PoVyrry&quot; data-user=&quot;tylergaw&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/tylergaw/pen/PoVyrry&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;This example uses &lt;code&gt;rgb&lt;/code&gt;, but a similar operation happens with &lt;code&gt;hsl&lt;/code&gt;, &lt;code&gt;hex&lt;/code&gt;, or a mix of color formats.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;add-vs-accumulate-and-the-curious-scale&quot;&gt;add vs accumulate, and the curious scale&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#add-vs-accumulate-and-the-curious-scale&quot; aria-labelledby=&quot;add-vs-accumulate-and-the-curious-scale&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In the examples so far, &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt; look the same. They do behave differently, but depending on the animated properties, there may not be a visible effect, or it may just be subtle. Let’s look at another example that shows a clear difference between the two and also shows that not all properties behave the same way.&lt;/p&gt;&lt;p&gt;In this example, we’ll animate a &lt;code&gt;scale&lt;/code&gt; transform. Our elements start at &lt;code&gt;scale(0.5)&lt;/code&gt; and animate to &lt;code&gt;scale(2)&lt;/code&gt;. We know the final &lt;code&gt;scale&lt;/code&gt; value for &lt;code&gt;replace&lt;/code&gt; will be &lt;code&gt;2&lt;/code&gt; or &lt;code&gt;200%&lt;/code&gt;. Looking at our previous examples, you would think we’d do the same basic math for &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt; where both would do 0.5 + 2 and end up with a scale of &lt;code&gt;2.5&lt;/code&gt; or &lt;code&gt;250%&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;But that’s not how &lt;code&gt;scale&lt;/code&gt; behaves. Take a look at the example and keep an eye on the &lt;code&gt;scale&lt;/code&gt; values in the table.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;mdvQbpV&quot; data-user=&quot;tylergaw&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/tylergaw/pen/mdvQbpV&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;We end up with &lt;code&gt;scale&lt;/code&gt; of &lt;code&gt;1&lt;/code&gt; for &lt;code&gt;add&lt;/code&gt; and a &lt;code&gt;scale&lt;/code&gt; of &lt;code&gt;1.5&lt;/code&gt; for &lt;code&gt;accumulate&lt;/code&gt;. Hrm, strange. But, it&amp;#39;s good that we’re finally seeing the two operations produce different results. &lt;/p&gt;&lt;p&gt;What’s the math here, though? 0.5 + 2 should be 2.5, right? Why isn’t that happening, and what is the math behind this? Unfortunately, I couldn’t find an answer before the publish deadline for this post. This does work the same in all browsers, so it doesn’t seem like a bug. Some underlying logic for &lt;code&gt;scale&lt;/code&gt; must make these the intended results. If you know the reason, please write about it!&lt;/p&gt;&lt;p&gt;Even with this, you still get more control over &lt;code&gt;scale&lt;/code&gt; – and any other properties that work the same way – it just takes some trial and error to get to the exact values you need.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;browser-support&quot;&gt;Browser support&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#browser-support&quot; aria-labelledby=&quot;browser-support&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Support for &lt;code&gt;animation-composition&lt;/code&gt; is good. According to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition#browser_compatibility&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN&lt;/a&gt;, recent versions of all major desktop and mobile browsers support the property. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Chrome 112&lt;/li&gt;&lt;li&gt;Firefox 115&lt;/li&gt;&lt;li&gt;Safari 16&lt;/li&gt;&lt;li&gt;Edge 112&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The standard caveat does apply here, though. While this property is implemented in browsers, it is still a W3C editor’s draft in&lt;a href=&quot;https://drafts.csswg.org/css-animations-2/#animation-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt; CSS Animations Level 2&lt;/a&gt;. That means the spec could change, and/or browsers may implement it differently. Always test in multiple browsers.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-it&quot;&gt;Using it&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#using-it&quot; aria-labelledby=&quot;using-it&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This is an interesting property. It’s likely not something you’ll use every day or even very often. It feels like something you’ll reach for when you’re trying to accomplish something very specific. That’s what makes it cool. It’s a low-level control for when you know exactly what you’re going after. And, if not that, it’s also helpful to toss on different values to play with random effects. Both are great reasons to use it. This property needs a healthy amount of trial and error to figure out how to make it work for you.&lt;/p&gt;&lt;p&gt;All the demos in this post and a couple more are available at &lt;a href=&quot;https://codepen.io/tylergaw/pen/VwgmrMY&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://codepen.io/tylergaw/pen/VwgmrMY&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/#reference&quot; aria-labelledby=&quot;reference&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;animation-composition on MDN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-animations-2/#animation-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;animation-composition in CSS Animations Level 2 Editor’s Draft&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Demos from this post &lt;a href=&quot;https://codepen.io/tylergaw/pen/VwgmrMY&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://codepen.io/tylergaw/pen/VwgmrMY&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://tylergaw.com/blog/&quot;&gt;Tyler Gaw&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/fa7f8d2d-6c8b-4b24-b9a7-75c9199059eb_tyler-gaw.jpg?auto=compress,format&amp;rect=0,0,1900,1900&amp;w=150&amp;h=150&quot; alt=&quot;Tyler Gaw&quot; /&gt;
  &lt;p&gt;Tyler is an engineer and designer. He&amp;#39;s spent his career in tech betting on The Web and pushing to help others see it for all it can be.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Tyler selected &lt;strong&gt;&lt;a href=&quot;https://www.girlsclub.org/&quot;&gt;The Lower Eastside Girls Club&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.girlsclub.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-invert-filter&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0abb29ef-0bc3-4e05-934a-baf05f4a41c4_lesgc.png?auto=compress,format&quot; alt=&quot;The Lower Eastside Girls Club&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Lower Eastside Girls Club amplifies the inner power of young women and gender-expansive youth in New York City through our free, year-round innovative programs in STEM, Arts, Digital Media and Sound, Wellness, Civic Engagement, and Leadership.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Web Components</title>
    <link href="https://12daysofweb.dev/2023/web-components/"/>
    <updated>2023-12-16T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/web-components/</id>
    <content type="html">



&lt;p&gt;&amp;quot;Web components&amp;quot; is an umbrella term for a set of modern web APIs that make it easier to work with the DOM. Broadly speaking, it includes three main features: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Custom elements &lt;/li&gt;&lt;li&gt;Shadow DOM &lt;/li&gt;&lt;li&gt;Slots and templates &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In this post, we&amp;#39;ll use web components to build a theme toggle that will allow us to switch between &lt;strong&gt;regular&lt;/strong&gt; and &lt;strong&gt;festive&lt;/strong&gt; themes. When the festive theme is active, it will start snowing, which is quite similar to this very site. &lt;/p&gt;&lt;p&gt;We&amp;#39;ll go through the important bits of HTML, CSS, and JavaScript in order. A complete CodePen demo can be found at the end. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;custom-elements&quot;&gt;Custom elements &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#custom-elements&quot; aria-labelledby=&quot;custom-elements&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This is a custom element: &lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;theme-toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;…&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;theme-toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Really, that&amp;#39;s it. Any element whose name contains a hyphen (&lt;code&gt;-&lt;/code&gt;) is a custom element. The naming restriction helps prevent conflicts with &amp;quot;built-in&amp;quot; elements. &lt;/p&gt;&lt;p&gt;So far, this is not that different from a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, but it has some useful capabilities, as we&amp;#39;ll see later. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;start-with-the-markup&quot;&gt;Start with the markup &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#start-with-the-markup&quot; aria-labelledby=&quot;start-with-the-markup&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s add all our important markup inside this custom element. For our theme toggle, we just need a &lt;code&gt;button&lt;/code&gt; with some text. We can wrap the text in a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; to make it easier to style later. &lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;theme-toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Festive theme&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;theme-toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make our toggle more accessible, we&amp;#39;ll implement the &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/switch/&quot; rel=&quot;noopener noreferrer&quot;&gt;switch pattern&lt;/a&gt;, which requires the &lt;code&gt;role=&amp;quot;switch&amp;quot;&lt;/code&gt; and &lt;code&gt;aria-checked&lt;/code&gt; attributes. When a screen-reader user accesses our button, they&amp;#39;ll hear something like &amp;quot;Festive theme, switch, &lt;strong&gt;off&lt;/strong&gt; (or &lt;strong&gt;on&lt;/strong&gt;)&amp;quot;. &lt;/p&gt;&lt;p&gt;These attributes could be added here in the initial markup, but since these don&amp;#39;t affect initial paint, and this pattern requires JavaScript to work anyway, let&amp;#39;s save them for later. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;style-like-you-normally-would&quot;&gt;Style like you normally would &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#style-like-you-normally-would&quot; aria-labelledby=&quot;style-like-you-normally-would&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We can reference custom elements in CSS selectors, just like we&amp;#39;d do for built-in HTML elements. Nothing new here (except the use of native CSS nesting). &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;theme-toggle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One important thing to mention, though, is &lt;code&gt;display&lt;/code&gt;. By default, custom elements are inline elements, but we usually want something like &lt;code&gt;inline-block&lt;/code&gt; or &lt;code&gt;block&lt;/code&gt; , so that it can be sized predictably. This is also a particularly &lt;a href=&quot;https://www.mayank.co/blog/use-cases-for-display-contents&quot; rel=&quot;noopener noreferrer&quot;&gt;good use case for &lt;code&gt;display: contents&lt;/code&gt;&lt;/a&gt;, since we care more about the button inside it. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;theme-toggle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;draw-the-rest-of-the-owl&quot;&gt;Draw the rest of the owl &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#draw-the-rest-of-the-owl&quot; aria-labelledby=&quot;draw-the-rest-of-the-owl&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;
    

    
    &lt;style&gt;
    /* &quot;-base&quot; is temporary for this step */
theme-toggle-base {
	display: contents;

	&amp; button {
		all: unset;
		display: grid;
		grid-template-areas: &quot;label&quot; &quot;toggle&quot;;
		place-items: center;
		gap: 4px;
		cursor: pointer;

		&amp;:hover,
		&amp;:focus-visible {
			&amp;::before {
				background-color: hsl(0 0% 50% / 0.2);
			}
		}

		&amp;:focus-visible {
			outline: 3px solid CanvasText;
			outline-offset: 2px;
		}

		&amp; span {
			grid-area: label;
			font-size: 1.5rem;
		}

		&amp;::before,
		&amp;::after {
			grid-area: toggle;
			content: &quot;&quot;;
			display: inline-block;
			border-radius: 9e9px;
			border: 3px solid;
		}

		&amp;::before {
			block-size: 70px;
			inline-size: 120px;
			transform: background-color 0.2s;
		}

		&amp;:after {
			block-size: 50px;
			aspect-ratio: 1;
			background: CanvasText;
			transform: translate(-50%);
			transition: transform 0.2s;
		}

		&amp;[aria-checked=&quot;true&quot;] {
			&amp;::after {
				content: &quot;&quot;;
				transform: translate(50%);
			}
			&amp; span::after {
				content: &quot;!!&quot;;
				position: absolute;
			}
		}
	}
}

@layer {
	.theme-toggle *,
	.theme-toggle ::before,
	.theme-toggle ::after {
		margin: 0;
		box-sizing: border-box;
	}
	.theme-toggle  {
		color-scheme: dark;
		background-color: Canvas;
		color: CanvasText;
		font-family: system-ui;
		display: grid;
		place-items: center;
		min-height: 30dvh;
	}
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;theme-toggle CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* &quot;-base&quot; is temporary for this step */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;theme-toggle-base&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;&amp;amp; button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;toggle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:hover,&lt;br /&gt;		&amp;amp;:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 50% / 0.2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px solid CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp; span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; label&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before,&lt;br /&gt;		&amp;amp;::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; toggle&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 9e9px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 70px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 120px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; background-color 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;[aria-checked=&quot;true&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp; span::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;!!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;.theme-toggle *,&lt;br /&gt;	.theme-toggle ::before,&lt;br /&gt;	.theme-toggle ::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;.theme-toggle&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Canvas&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30dvh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;theme-toggle&quot;&gt;
  &lt;theme-toggle-base&gt;
    &lt;button type=&quot;button&quot;&gt;
      &lt;span&gt;Festive theme&lt;/span&gt;
    &lt;/button&gt;
  &lt;/theme-toggle-base&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;The CSS is quite simple. Here are some of the interesting points: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;The button implements a two-row grid to place the toggle below the label.&lt;/li&gt;&lt;li&gt;The toggle is created using the &lt;code&gt;::before&lt;/code&gt; (for the &amp;quot;outer&amp;quot; border) and &lt;code&gt;::after&lt;/code&gt; (for the &amp;quot;inner&amp;quot; switch) pseudo-elements. &lt;/li&gt;&lt;li&gt;&lt;code&gt;[aria-checked=&amp;#39;true&amp;#39;]&lt;/code&gt; is reused as a &lt;a href=&quot;https://benmyers.dev/blog/semantic-selectors/&quot; rel=&quot;noopener noreferrer&quot;&gt;stateful semantic selector&lt;/a&gt;, avoiding the need for an additional class/attribute. &lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;lets-enhance&quot;&gt;Let&#39;s enhance &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#lets-enhance&quot; aria-labelledby=&quot;lets-enhance&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We are now ready to &amp;quot;enhance&amp;quot; our custom element with JavaScript behavior. &lt;/p&gt;&lt;p&gt;A custom element must be written as a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot; rel=&quot;noopener noreferrer&quot;&gt;JavaScript class&lt;/a&gt; which extends the &lt;code&gt;HTMLElement&lt;/code&gt; interface. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then, it can be associated with a tag name using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;customElements.define()&lt;/code&gt; method&lt;/a&gt; (available globally under &lt;code&gt;window&lt;/code&gt; ).&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;theme-toggle&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThemeToggle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This makes sense! Do you know how when we create or query for a built-in element like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, we return an instance of &lt;code&gt;HTMLButtonElement&lt;/code&gt;? Similarly, when we query for &lt;code&gt;&amp;lt;theme-toggle&amp;gt;&lt;/code&gt;, we&amp;#39;ll get back an instance of &lt;code&gt;ThemeToggle&lt;/code&gt;. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;what-is-this&quot;&gt;What is this? &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#what-is-this&quot; aria-labelledby=&quot;what-is-this&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Inside a JavaScript class, we expect the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;this&lt;/code&gt; keyword&lt;/a&gt; to refer to an instance of the class. &lt;code&gt;this&lt;/code&gt; is how we&amp;#39;re able to access the instance fields and methods defined in our class. And since we&amp;#39;re extending the &lt;code&gt;HTMLElement&lt;/code&gt; interface, this also gives us access to all the regular DOM methods, like &lt;code&gt;querySelector&lt;/code&gt; and &lt;code&gt;innerHTML&lt;/code&gt; . &lt;/p&gt;&lt;p&gt;There are many ways &lt;code&gt;this&lt;/code&gt; can go wrong, especially when dealing with event listeners. Instead of doing a deep dive on &lt;code&gt;this&lt;/code&gt;, I will suggest a simple rule that helps avoid most of the confusion: only pass around &lt;strong&gt;arrow functions&lt;/strong&gt;. The arrow function can contain the entire logic or simply call an instance method. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌&lt;/span&gt;&lt;br /&gt;something&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ✅&lt;/span&gt;&lt;br /&gt;something&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;connectedcallback-all-the-things&quot;&gt;connectedCallback all the things &lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#connectedcallback-all-the-things&quot; aria-labelledby=&quot;connectedcallback-all-the-things&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When defining our class, we can use a bunch of handy &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Components/Using_custom_elements#custom_element_lifecycle_callbacks&quot; rel=&quot;noopener noreferrer&quot;&gt;lifecycle methods&lt;/a&gt; that will always be called in a predictable fashion. The most important one is &lt;code&gt;connectedCallback&lt;/code&gt;, which gets called when the custom element is added to the document. We can set up most of our component logic here. &lt;/p&gt;&lt;p&gt;First, grab our button and add the required attributes for the switch pattern we discussed earlier. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;role&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;switch&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;aria-checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;false&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt; &lt;code&gt;this.querySelector(&amp;quot;button&amp;quot;)&lt;/code&gt; will give us the first button inside our &lt;code&gt;&amp;lt;theme toggle&amp;gt;&lt;/code&gt; rather than the first button in the document. When called on an element, &lt;code&gt;querySelector&lt;/code&gt; is scoped to it and supports additional features, like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:scope#using_scope_in_javascript&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;:scope&lt;/code&gt; pseudo class&lt;/a&gt;, which can be handy for querying complex selectors. &lt;/p&gt;&lt;/aside&gt;&lt;p&gt;Now, let&amp;#39;s add a &amp;quot;click&amp;quot; event handler to the button. The main thing we&amp;#39;ll do is toggle the &lt;code&gt;aria-checked&lt;/code&gt; attribute&amp;#39;s value. Our CSS already knows how to react to this attribute, so we don&amp;#39;t need to do anything else to make the toggle work. We&amp;#39;ll also add a snowfall effect shortly, but for now, let&amp;#39;s just store its state in an instance field &lt;code&gt;this.snowing&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;aria-checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And just like that, our toggle switch works!&lt;/p&gt;&lt;p&gt;Our deliberate choice to use a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element as the base means that it will be automatically keyboard-focusable and the click handler will also be automatically called when pressing the &lt;code&gt;Enter&lt;/code&gt; or &lt;code&gt;Spacebar&lt;/code&gt; keys. &lt;/p&gt;
    

    
    &lt;style&gt;
    theme-toggle {
	display: contents;

	&amp; button {
		all: unset;
		display: grid;
		grid-template-areas: &quot;label&quot; &quot;toggle&quot;;
		place-items: center;
		gap: 4px;
		cursor: pointer;

		&amp;:hover,
		&amp;:focus-visible {
			&amp;::before {
				background-color: hsl(0 0% 50% / 0.2);
			}
		}

		&amp;:focus-visible {
			outline: 3px solid CanvasText;
			outline-offset: 2px;
		}

		&amp; span {
			grid-area: label;
			font-size: 1.5rem;
		}

		&amp;::before,
		&amp;::after {
			grid-area: toggle;
			content: &quot;&quot;;
			display: inline-block;
			border-radius: 9e9px;
			border: 3px solid;
		}

		&amp;::before {
			block-size: 70px;
			inline-size: 120px;
			transform: background-color 0.2s;
		}

		&amp;:after {
			block-size: 50px;
			aspect-ratio: 1;
			background: CanvasText;
			transform: translate(-50%);
			transition: transform 0.2s;
		}

		&amp;[aria-checked=&quot;true&quot;] {
			&amp;::after {
				content: &quot;&quot;;
				transform: translate(50%);
			}
			&amp; span::after {
				content: &quot;!!&quot;;
				position: absolute;
			}
		}
	}
}

@layer {
	.theme-toggle *,
	.theme-toggle ::before,
	.theme-toggle ::after {
		margin: 0;
		box-sizing: border-box;
	}
	.theme-toggle  {
		color-scheme: dark;
		background-color: Canvas;
		color: CanvasText;
		font-family: system-ui;
		display: grid;
		place-items: center;
		min-height: 30dvh;
	}
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;theme-toggle connectedCallback&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;theme-toggle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;&amp;amp; button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;toggle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:hover,&lt;br /&gt;		&amp;amp;:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 50% / 0.2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px solid CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp; span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; label&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before,&lt;br /&gt;		&amp;amp;::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; toggle&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 9e9px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 70px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 120px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; background-color 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;:after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;		&lt;span class=&quot;token selector&quot;&gt;&amp;amp;[aria-checked=&quot;true&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp;::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token selector&quot;&gt;&amp;amp; span::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;!!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;				&lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;.theme-toggle *,&lt;br /&gt;	.theme-toggle ::before,&lt;br /&gt;	.theme-toggle ::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token selector&quot;&gt;.theme-toggle&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Canvas&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30dvh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;switch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-checked&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-checked&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snowing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;theme-toggle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThemeToggle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;theme-toggle&quot;&gt;
  &lt;theme-toggle&gt;
    &lt;button type=&quot;button&quot;&gt;
      &lt;span&gt;Festive theme&lt;/span&gt;
    &lt;/button&gt;
  &lt;/theme-toggle&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    class ThemeToggle extends HTMLElement {
  connectedCallback() {
    const button = this.querySelector(&quot;button&quot;);
    button.setAttribute(&quot;role&quot;, &quot;switch&quot;);
    button.setAttribute(&quot;aria-checked&quot;, &quot;false&quot;);

    button.addEventListener(
      &quot;click&quot;,
      () =&gt; {
        this.snowing = !this.snowing;
        button.setAttribute(&quot;aria-checked&quot;, this.snowing);
      }
    );
  }
}

customElements.define(&quot;theme-toggle&quot;, ThemeToggle);
    &lt;/script&gt;
    

    

    
    &lt;p&gt;How cool is that?! Our custom element can manage its own lifecycle independently. No need to mess with &lt;a href=&quot;https://javascript.info/onload-ondomcontentloaded&quot; rel=&quot;noopener noreferrer&quot;&gt;DOM ready events&lt;/a&gt; (which are &lt;a href=&quot;https://www.youtube.com/watch?v=_iq1fPjeqMQ&quot; rel=&quot;noopener noreferrer&quot;&gt;unreliable&lt;/a&gt;) or &lt;a href=&quot;https://javascript.info/mutation-observer&quot; rel=&quot;noopener noreferrer&quot;&gt;mutation observers&lt;/a&gt; (which are tedious). &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;cleanup&quot;&gt;Cleanup &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#cleanup&quot; aria-labelledby=&quot;cleanup&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;disconnectedCallback&lt;/code&gt; lifecycle method gets called when the custom element is removed from the document. It is good practice to remove event listeners (and do other &amp;quot;cleanup&amp;quot;) inside this method, especially when building for highly dynamic websites. &lt;/p&gt;&lt;p&gt;The best way to remove event listeners is using an &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortController&quot; rel=&quot;noopener noreferrer&quot;&gt;AbortController&lt;/a&gt;&lt;/code&gt;. This is done in three steps: &lt;/p&gt;&lt;ol&gt;&lt;li&gt;Store the controller in an instance field. &lt;/li&gt;&lt;li&gt;Pass its &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal&quot; rel=&quot;noopener noreferrer&quot;&gt;abort signal&lt;/a&gt; when adding event listeners. The same signal can be reused for multiple event listeners. &lt;/li&gt;&lt;li&gt;In &lt;code&gt;disconnectedCallback&lt;/code&gt;, call &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort&quot; rel=&quot;noopener noreferrer&quot;&gt;abort()&lt;/a&gt;&lt;/code&gt; to remove all event listeners together. There is no need to hold on to references to every individual event listener. &lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; signal &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;controller &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AbortController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/*…*/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; signal &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;controller&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;shadow-dom&quot;&gt;Shadow DOM &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#shadow-dom&quot; aria-labelledby=&quot;shadow-dom&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Shadow DOM is another web component API that is used for attaching a &amp;quot;hidden&amp;quot; DOM tree to an element. This tree is encapsulated from the rest of the document, which means its styles and IDs won&amp;#39;t &amp;quot;leak&amp;quot; out and vice-versa. &lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt; Shadow DOM introduces many &lt;a href=&quot;https://www.matuzo.at/blog/2023/pros-and-cons-of-shadow-dom/&quot; rel=&quot;noopener noreferrer&quot;&gt;styling and accessibility issues&lt;/a&gt;, which subsequently need elaborate workarounds. It is generally a good idea to start with a shadowless custom element because it allows us to take advantage of many aspects of web components while keeping our existing mental models intact. Instead of reaching for shadow DOM by default, it should be considered on a case-by-case basis. &lt;/p&gt;&lt;/aside&gt;&lt;p&gt;One interesting thing to note: a shadow DOM tree does not always need to be attached to custom elements; it can also be attached to many built-in elements (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#elements_you_can_attach_a_shadow_to&quot; rel=&quot;noopener noreferrer&quot;&gt;see full list&lt;/a&gt;). &lt;/p&gt;&lt;p&gt;With that in mind, let&amp;#39;s build our snowfall effect. Since this effect will likely require a bunch of otherwise meaningless elements, we can use shadow DOM to avoid cluttering our main HTML. Shadow DOM is particularly good at hiding such purely presentational elements. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s attach a shadow tree to the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;attachShadow&lt;/code&gt; method&lt;/a&gt;. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setupSnowfall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;setupSnowfall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Some interesting notes: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;We usually want to set &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/mode&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;mode&lt;/code&gt;&lt;/a&gt; to &amp;quot;open&amp;quot; unless there is a good reason to prevent other JavaScript code from accessing this shadow tree. &lt;/li&gt;&lt;li&gt;Since &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; is a shared element, it may already have a shadow tree attached to it. We can check for it using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot&quot; rel=&quot;noopener noreferrer&quot;&gt;the &lt;code&gt;.shadowRoot&lt;/code&gt; property&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;For more robustness, it may be better to attach a shadow tree to another element and append that element to &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. However, I&amp;#39;m using &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; here for simplicity and to demonstrate slots in the next section. &lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;slots&quot;&gt;Slots &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#slots&quot; aria-labelledby=&quot;slots&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;By default, shadow trees will &amp;quot;replace&amp;quot; all the content of the element that it&amp;#39;s attached to. We definitely want to keep our &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; content around. We can do that using a &amp;quot;slot&amp;quot;. &lt;/p&gt;&lt;p&gt;Slots are an important tool that provides a way to mix and match parts of shadow DOM and &amp;quot;light&amp;quot; DOM. As a general pattern, we can use slots to keep our semantically important parts in the light DOM and hide implementation details in shadow DOM. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s add &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Slot&quot; rel=&quot;noopener noreferrer&quot;&gt;a &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; element&lt;/a&gt; into our shadow tree. All the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; content will be automatically filled into this slot.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// … &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;setupSnowfall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// … &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; slot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;slot&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;slot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;make-it-snow&quot;&gt;Make it snow &lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#make-it-snow&quot; aria-labelledby=&quot;make-it-snow&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now for the fun part: the snowfall effect! There are probably better ways to do this, but I will show off a simple SVG. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;This SVG will cover up the entire viewport, so its viewBox is based on &lt;code&gt;window.innerHeight&lt;/code&gt; and &lt;code&gt;window.innerWidth&lt;/code&gt;. &lt;/li&gt;&lt;li&gt;Since it should not occupy any space, we can use &lt;code&gt;position: fixed&lt;/code&gt;. Any CSS written inside shadow DOM is automatically &lt;strong&gt;scoped&lt;/strong&gt; to the elements within this tree, so we&amp;#39;ll just use &lt;code&gt;svg&lt;/code&gt; as the selector. &lt;/li&gt;&lt;li&gt;Inside the SVG, we&amp;#39;ll place a bunch of &lt;code&gt;&amp;lt;circle&amp;gt;&lt;/code&gt;s at random spots and use &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt; to make them move across the screen. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I won&amp;#39;t show the full code because, as far as our web component is concerned, all we&amp;#39;re doing is inserting HTML into the shadow tree. You&amp;#39;ll find the full CodePen below. &lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;setupSnowfall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;innerWidth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;innerHeight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; h &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     slot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;beforebegin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#92;&lt;br /&gt;       &amp;lt;style&gt;&lt;br /&gt;        svg { position: fixed; inset: 0; }&lt;br /&gt;       &amp;lt;/style&gt;&lt;br /&gt;       &amp;lt;svg viewBox=&quot;0 0 &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;w&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;h&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; aria-hidden=&quot;true&quot;&gt;&lt;br /&gt;         &amp;lt;circle&gt;…&amp;lt;/circle&gt;&lt;br /&gt;         &amp;lt;circle&gt;…&amp;lt;/circle&gt;&lt;br /&gt;         &amp;lt;circle&gt;…&amp;lt;/circle&gt;&lt;br /&gt;         …&lt;br /&gt;       &amp;lt;/svg&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lastly, all we need to do is toggle the snow when the button is clicked. I like to use a combination of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set&quot; rel=&quot;noopener noreferrer&quot;&gt;setters&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties&quot; rel=&quot;noopener noreferrer&quot;&gt;private properties&lt;/a&gt; for this sort of logic. Our click handler already toggles &lt;code&gt;this.snowing&lt;/code&gt; so let&amp;#39;s just convert that into a setter. We&amp;#39;ll execute the logic of starting/stopping the animation whenever the setter function is called.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThemeToggle&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// … &lt;/span&gt;&lt;br /&gt;  #snowing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;snowing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#snowing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;snowing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;snowing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#snowing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; snowing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; svg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;svg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; svg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;animate&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snowing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;endElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we&amp;#39;re done! &lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;ZEwqNRM&quot; data-user=&quot;MrRoboto&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/MrRoboto/pen/ZEwqNRM&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;go-further&quot;&gt;Go further&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/web-components/#go-further&quot; aria-labelledby=&quot;go-further&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While we&amp;#39;ve covered most of the important bits of web components, there&amp;#39;s a lot more to it! &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Components/Using_custom_elements#responding_to_attribute_changes&quot; rel=&quot;noopener noreferrer&quot;&gt;Custom elements can &amp;quot;react&amp;quot; to attribute changes&lt;/a&gt; using &lt;code&gt;observedAttributes&lt;/code&gt; and &lt;code&gt;attributeChangedCallback&lt;/code&gt;. &lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:defined&quot; rel=&quot;noopener noreferrer&quot;&gt;:defined&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined&quot; rel=&quot;noopener noreferrer&quot;&gt;:whenDefined&lt;/a&gt;&lt;/code&gt; are great for improving the &lt;a href=&quot;https://archive.hankchizljaw.com/wrote/the-power-of-progressive-enhancement/&quot; rel=&quot;noopener noreferrer&quot;&gt;progressively enhanced experience&lt;/a&gt; of custom elements. &lt;/li&gt;&lt;li&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; element&lt;/a&gt; can be used to store &amp;quot;inert&amp;quot; HTML and avoid having to create elements inside JS. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://javascript.info/slots-composition#named-slots&quot; rel=&quot;noopener noreferrer&quot;&gt;Named slots&lt;/a&gt; can be used to control which content fills which part of the template. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events&quot; rel=&quot;noopener noreferrer&quot;&gt;Custom events&lt;/a&gt; can be dispatched from a custom element to communicate with other parts of the document. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/articles/declarative-shadow-dom/&quot; rel=&quot;noopener noreferrer&quot;&gt;Declarative shadow DOM&lt;/a&gt; (once available cross-browser) will let us attach shadow trees without any JS! &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_shadow_parts&quot; rel=&quot;noopener noreferrer&quot;&gt;Shadow parts&lt;/a&gt; can be used to selectively allow external styling of nodes within a shadow tree. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/constructable-stylesheets&quot; rel=&quot;noopener noreferrer&quot;&gt;Constructable stylesheets&lt;/a&gt; provide a performant way to write CSS-in-JS. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://enhance.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;Server-first frameworks&lt;/a&gt; can be used to &lt;a href=&quot;https://www.mayank.co/blog/web-components-are-not-components&quot; rel=&quot;noopener noreferrer&quot;&gt;make shadowless web components portable&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;Most UI frameworks have good support for &lt;a href=&quot;https://custom-elements-everywhere.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;consuming web components&lt;/a&gt;. Some frameworks can also &lt;a href=&quot;https://svelte.dev/docs/custom-elements-api&quot; rel=&quot;noopener noreferrer&quot;&gt;compile to web components&lt;/a&gt;, while others &lt;a href=&quot;https://lit.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;only allow writing&lt;/a&gt; web components.&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://www.mayank.co/&quot;&gt;Mayank&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/a6be90f2-9d0e-44fd-a6da-d50e2a0dbea5_mayank.jpeg?auto=compress,format&amp;rect=0,0,460,460&amp;w=150&amp;h=150&quot; alt=&quot;Mayank&quot; /&gt;
  &lt;p&gt;I&amp;#39;m a design engineer who loves all things CSS and accessibility. I like building websites that solve real problems without compromising user experience. In my free time, you&amp;#39;ll find me hacking on side projects and writing about code (when I&amp;#39;m not occupied with djent and progressive metal).&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Mayank selected &lt;strong&gt;&lt;a href=&quot;https://translifeline.org/&quot;&gt;Trans Lifeline&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://translifeline.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/a3fa386c-2a3d-47b2-84f4-72275c2c1fc4_trans-lifeline.webp?auto=compress,format&quot; alt=&quot;Trans Lifeline&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Trans Lifeline provides direct emotional and financial support to trans people in crisis, in the United States and Canada.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS @scope</title>
    <link href="https://12daysofweb.dev/2023/css-scope/"/>
    <updated>2023-12-15T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/css-scope/</id>
    <content type="html">



&lt;p&gt;&lt;em&gt;Scoped styles&lt;/em&gt; have always been the primary goal of CSS. Selectors scope declarations to matched elements. Those selectors can be combined to create &lt;em&gt;more specific&lt;/em&gt; scopes – each modified by its relation to others. But the &lt;code&gt;@scope&lt;/code&gt; feature, already available in Chromium browsers, will make that functionality even more powerful.&lt;/p&gt;&lt;p&gt;Historically, relational selectors were limited in what scopes they could express, and the results can feel fragile if we’re not careful. Narrow relations like the &lt;code&gt;&amp;gt;&lt;/code&gt; ‘child’ combinator break if we add a wrapping element around the child. Broader relations like the ‘descendant’ combinator can easily bleed into nested content. That’s fine when we really mean ‘direct children’ or ‘all descendants’ – but often, we’re trying to express a more abstract idea of &lt;em&gt;belonging&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Some styles are global, but many styles &lt;em&gt;belong to a component.&lt;/em&gt; When we select the &lt;code&gt;article .title&lt;/code&gt; we don’t necessarily want all the &lt;code&gt;.title&lt;/code&gt; elements inside the &lt;code&gt;article&lt;/code&gt;, but specifically &lt;em&gt;the&lt;/em&gt; .&lt;code&gt;title&lt;/code&gt; &lt;em&gt;that belongs to the article&lt;/em&gt;. This is what people mean when they ask for &lt;em&gt;scope&lt;/em&gt; in CSS. Selectors that convey not just &lt;em&gt;nesting&lt;/em&gt;, but &lt;em&gt;belonging&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Nicole Sullivan pointed &lt;a href=&quot;https://www.slideshare.net/stubbornella/object-oriented-css#62&quot; rel=&quot;noopener noreferrer&quot;&gt;to these issues back in 2009&lt;/a&gt;, and since then authors have developed a number of elaborate workarounds. The BEM (e.g. block-element--modifier) naming convention has been dominant for over a decade, with more and more third-party tools providing ‘scoped styles’ as a build step.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;fifteen-years-of-scope-hacks&quot;&gt;Fifteen years of scope hacks&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#fifteen-years-of-scope-hacks&quot; aria-labelledby=&quot;fifteen-years-of-scope-hacks&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To express &lt;em&gt;belonging&lt;/em&gt; in CSS, we need two parts – what BEM would call the ‘block’ and the ‘element.’ Elements belong to blocks. To make that relation clearer than simply nesting, BEM requires adding the block name to every element and selector in the scope: &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* nesting: all matching elements in the block */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.block .element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* BEM: just the elements belonging to the block */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.block-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Most front-end frameworks now provide &lt;em&gt;scoped styles&lt;/em&gt;, generating unique block names and appending them to elements automatically:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Frameworks (the details vary) */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.element[data-scope=block]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But naming conventions require strict adherence across an organization, and automation requires full control of both the HTML and CSS output in a single build step. It’s an invasive process that applies unique attributes throughout the DOM and appends them to every relevant selector. &lt;/p&gt;&lt;p&gt;These are not reliable solutions to the problem; they’re hacks we’ve grown used to over the last fifteen years.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;re-introducing-css-scope&quot;&gt;(Re-) Introducing CSS @scope&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#re-introducing-css-scope&quot; aria-labelledby=&quot;re-introducing-css-scope&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The new CSS &lt;code&gt;@scope&lt;/code&gt; rule allows us to define a scoped relationship in two parts. First, we define the block itself by selecting the ‘root’ of a given scope. Those selectors go in the ‘prelude’ to the rule:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, we can define ‘scoped’ selectors that belong in the scope of that block:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This might be familiar if you’ve used CSS nesting. It will select the same elements as either of the following:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.block&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.block .element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With nesting, there’s an implicit &lt;code&gt;&amp;amp;&lt;/code&gt; before each nested selector, but you can also place the &lt;code&gt;&amp;amp;&lt;/code&gt; explicitly if you want. The &lt;code&gt;&amp;amp;&lt;/code&gt; selector is a stand-in for the nesting parent:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.block&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* implied starting &amp;amp; */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; .element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* explicit starting &amp;amp; */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.context &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* repositioned &amp;amp; */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Scope works the same way, but using the &lt;code&gt;:scope&lt;/code&gt; selector by default:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* implied starting :scope */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:scope .element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* explicit starting :scope */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.context :scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* repositioned :scope */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;They look similar, but don’t let that fool you. CSS nesting is a shorthand for writing multi-part (&lt;a href=&quot;https://www.miriamsuzanne.com/2022/06/15/complex-compound/&quot; rel=&quot;noopener noreferrer&quot;&gt;complex&lt;/a&gt;) selectors. But despite being written in multiple steps, the resulting selectors only match a single element: the final ‘subject’ of the combined selector. Nested relationships can be referenced along the way to narrow down our subjects, but those relationships don’t ‘stick around’ after selection is complete. &lt;/p&gt;&lt;p&gt;To make the scope more meaningful in the cascade, we need to know both the element that we’re styling and also &lt;em&gt;the blocks that it belongs to.&lt;/em&gt; The scope rule achieves that by explicitly breaking selection into two distinct parts with two distinct targets: a scope-root selector and a subject-element selector. That subtle change makes all the difference.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;scope-proximity&quot;&gt;Scope Proximity&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#scope-proximity&quot; aria-labelledby=&quot;scope-proximity&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Because we know the relationship between the subject and the scope it belongs to, we can do things like &lt;em&gt;measure their proximity&lt;/em&gt; – the number of DOM steps between them:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;’block’&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;’element’&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Only 1 step &lt;br /&gt;    from .element to .block.&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;footer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;’element’&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        3 steps from .element&lt;br /&gt;        (through div and footer) &lt;br /&gt;        to .block.&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;footer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/css-cascade-6/#cascade-proximity&quot; rel=&quot;noopener noreferrer&quot;&gt;Scope proximity&lt;/a&gt; has been added to the cascade after &lt;em&gt;selector specificity&lt;/em&gt; but before &lt;em&gt;order of appearance&lt;/em&gt;. When two selectors with equal specificity apply to the same element, the selector with a ‘closer’ scope-root will win.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;wvyBNXP&quot; data-user=&quot;miriamsuzanne&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/miriamsuzanne/pen/wvyBNXP&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;This is especially helpful in situations where the two selectors serve the same purpose, and we might want broadly overlapping scopes – like setting link colors from different themes. But other ways exist to achieve a similar result, like custom properties (which inherit based on proximity). Things get more exciting when we add a third selector to the syntax.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;scope-boundaries&quot;&gt;Scope Boundaries&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#scope-boundaries&quot; aria-labelledby=&quot;scope-boundaries&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The real power of a component-based approach is the ability to &lt;em&gt;compose&lt;/em&gt; new patterns by combining blocks in various ways. The ‘tabs’ component is only useful when we put other content inside each tab panel. However, the tab element doesn’t know what that content will be, so the scope of our ‘tab’ component styles should stop where the content begins. Nicole calls that ‘donut scope’ – when components have a hole in the middle (or a slot) for other content to go inside.&lt;/p&gt;&lt;p&gt;That causes a problem for nested selectors, which apply to &lt;em&gt;all descendants equally&lt;/em&gt;. So we rely instead on third-party tools and BEM syntax to generate unique identifiers and apply them to each element in the donut. The &lt;code&gt;@scope&lt;/code&gt; rule makes that possible without any conventions or tools. We can provide a second selector in the prelude:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; to &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.slot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can see this work in any up-to-date Chromium browser:&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;XWZwvWj&quot; data-user=&quot;miriamsuzanne&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/miriamsuzanne/pen/XWZwvWj&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;There’s a cool trick &lt;a href=&quot;https://chriskirknielsen.com/blog/select-an-element-which-doesnt-descend-from-another-in-css/&quot; rel=&quot;noopener noreferrer&quot;&gt;with the :not() selector&lt;/a&gt; that will get you close, but it fails if you start nesting scopes. Creating an isolated donut requires understanding the DOM relationship between each &lt;em&gt;root&lt;/em&gt;, &lt;em&gt;boundary&lt;/em&gt;, and &lt;em&gt;subject&lt;/em&gt; element on the page – so it requires three distinct selectors to make it work.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;scoped-rules-keep-specificity-low&quot;&gt;Scoped Rules Keep Specificity Low&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#scoped-rules-keep-specificity-low&quot; aria-labelledby=&quot;scoped-rules-keep-specificity-low&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Another big difference between nesting and &lt;code&gt;@scope&lt;/code&gt; is the specificity of the selectors. Nested selectors are combined into one, with a combined specificity to match:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#banner&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* specificity: [1, 0, 1] */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But with scope, we use two or three distinct selectors. They are never joined together, and so they don’t result in a combined specificity:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;#banner&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* specificity: [0, 0, 1] */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Many authors like that BEM syntax ‘flattens’ specificity by using a single class for everything. But selection is half of what CSS does! If we can only use classes, we’re giving up some of the most powerful and expressive features in the language. By using scope instead of nesting when it makes sense, we can get the best of both worlds!&lt;/p&gt;&lt;p&gt;Using an explicit &lt;code&gt;:scope&lt;/code&gt; selector will add some specificity – a pseudo-class has the same specificity as a normal class. It refers to the scope root element but without directly referencing the scope-root selector. If we do want to combine the two selectors and get their combined specificity, we can use the &lt;code&gt;&amp;amp;&lt;/code&gt; instead:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;#banner&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* specificity: [0, 1, 1] */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:scope h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* specificity: [1, 0, 1] */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;implicit-scopes-and-embedded-styles&quot;&gt;Implicit Scopes and Embedded Styles&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#implicit-scopes-and-embedded-styles&quot; aria-labelledby=&quot;implicit-scopes-and-embedded-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Sometimes, it can be useful to embed styles directly in the page along with the component that they style. We can use scopes there, too! An &lt;code&gt;@scope&lt;/code&gt; rule without a defined root selector will use the parent element as an implicit scope root:&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;ExrdXrZ&quot; data-user=&quot;miriamsuzanne&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/miriamsuzanne/pen/ExrdXrZ&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;bringing-it-all-together&quot;&gt;Bringing it all together&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/css-scope/#bringing-it-all-together&quot; aria-labelledby=&quot;bringing-it-all-together&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;I don’t want to make it sound like scope and nesting are in competition here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use &lt;code&gt;@scope&lt;/code&gt; to define specific patterns or components and their block-element relationships. Those can be broad (entire themes) or narrow (single buttons) and might overlap sometimes. It’s fine for elements to belong in multiple scopes, but each scope is specific to some &lt;em&gt;fragment of the DOM&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;Nesting exists to make complex selectors more readable. It can handle a wider variety of selectors than &lt;code&gt;@scope&lt;/code&gt; because it is not designed for one specific use-case. While &lt;code&gt;@scope&lt;/code&gt; is excellent at expressing the &lt;code&gt;block-element&lt;/code&gt; relationship, nesting is still the clear choice for the &lt;code&gt;element--modifier&lt;/code&gt; relationships, like pseudo-classes.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some other recent features overlap with scope in interesting ways:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use &lt;code&gt;@layer&lt;/code&gt; to group and prioritize different styling concerns. They tend to be more broad and architectural – resets, frameworks, design systems, and utilities – and apply to any number of components. A button component and a theme component might both start with ‘default’ layers.&lt;/li&gt;&lt;li&gt;Scope roots will often be good container elements for &lt;code&gt;@container&lt;/code&gt; queries. I expect it will be common to see &lt;code&gt;:scope { container: my-scope-name / inline-size; }&lt;/code&gt; at the top of many &lt;code&gt;@scope&lt;/code&gt; rules. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Happy scoping!&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://www.miriamsuzanne.com/&quot;&gt;Miriam Suzanne&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/7d3d287a-dee5-4968-80cd-8ff4599432cf_miriam.jpeg?auto=compress,format&amp;rect=158,0,640,640&amp;w=150&amp;h=150&quot; alt=&quot;Miriam Suzanne&quot; /&gt;
  &lt;p&gt;Miriam is an artist, engineer, and open-web advocate. She’s a co-founder of &lt;a href=&quot;https://oddbird.net/&quot; rel=&quot;noopener noreferrer&quot;&gt;OddBird&lt;/a&gt;, Invited Expert on the &lt;a href=&quot;https://www.w3.org/Style/CSS/members&quot; rel=&quot;noopener noreferrer&quot;&gt;W3C CSS Working Group&lt;/a&gt;, and &lt;a href=&quot;https://sass-lang.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Sass&lt;/a&gt; core contributor who enjoys pushing the boundaries of web technology. These days she’s working on specifications for Container Queries, Scope, and Cascade Layers in CSS; extending the Sass color module to support wide-gamut colors; and learning to crochet socks.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Miriam selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Anchor Positioning</title>
    <link href="https://12daysofweb.dev/2023/anchor-positioning/"/>
    <updated>2023-12-14T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/anchor-positioning/</id>
    <content type="html">



&lt;p&gt;Imagine &lt;a href=&quot;https://drafts.csswg.org/css-flexbox/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Flexbox&lt;/a&gt; without the ability to use the flex property. Imagine &lt;a href=&quot;https://drafts.csswg.org/css-grid/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Grid&lt;/a&gt; without an ability to use &lt;code&gt;repeat()&lt;/code&gt; for its templates, or an ability to configure &lt;code&gt;grid-column&lt;/code&gt; and &lt;code&gt;grid-row&lt;/code&gt; for specific elements. Without these essential features, these layout methods will not make much sense.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/a5ac480a-cc03-465c-8697-b6d73ab6d387_anchor-positioning.jpg?auto=compress,format&quot; alt=&quot;An illustration showing a big, slightly rotated anchor emoji on a black background with a green bubble pointing to it. The bubble contains the text “Hello!”. There are two light-blue dashed lines, one vertical and one horizontal, intersecting the point where the anchor and bubble touch. Above the horizontal line, there is an “inset-inline = ?” text, and on a side of the vertical one there is “inset-block = ?”. In the bottom-right section of the illustration, the text “Anchor Positioning” is written in a bigger font over two slightly rotated lines. An icon of a paper airplane with a dashed line after it is placed on the right of the word “Anchor”, as if launched by it.&quot; /&gt;&lt;figcaption&gt;&lt;a href=&quot;https://codepen.io/kizu/pen/jOdvWXG&quot; rel=&quot;noopener noreferrer&quot;&gt;Illustration source&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;In a few years, after anchor positioning will become available in all browsers, we will look back at it and think: “How could we use it without anchors?” — that’s what I can say now, after experimenting with today’s anchor positioning prototypes and thinking about its specs.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-disclaimer&quot;&gt;The Disclaimer&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#the-disclaimer&quot; aria-labelledby=&quot;the-disclaimer&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The first thing that needs to be said before discussing anchor positioning is — its current status.&lt;/p&gt;&lt;p&gt;Today, we cannot use anchor positioning in any regard. It is not ready.&lt;/p&gt;&lt;p&gt;The specification is evolving and improving; it is not done yet. While &lt;a href=&quot;https://www.w3.org/TR/css-anchor-position-1/&quot; rel=&quot;noopener noreferrer&quot;&gt;the first Working Draft&lt;/a&gt; was published in June, since then, there have been developments (see the &lt;a href=&quot;about:blank#Area-based%20Positioning&quot; rel=&quot;noopener noreferrer&quot;&gt;Area-based Positioning&lt;/a&gt; section), which resulted in many additions to &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/&quot; rel=&quot;noopener noreferrer&quot;&gt;the current Editor’s Draft&lt;/a&gt;. Furthermore, there are &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+%27css-anchor%27&quot; rel=&quot;noopener noreferrer&quot;&gt;close to 50 open issues&lt;/a&gt;, and it is uncertain what the specification will include when it will be ready.&lt;/p&gt;&lt;p&gt;That said, even today, there is a lot to play with!&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;You might want to open the examples you will see in the latest Chrome Canary with the “experimental web platform features” feature flag turned on so you can play with them yourself!&lt;/p&gt;&lt;p&gt;In this post, I won’t provide a “tutorial” on how to use anchor positioning. It is a large specification, and as it is not finalized, any tutorial will soon be outdated. If you’d want to read something besides the specification, I recommend &lt;a href=&quot;https://developer.chrome.com/blog/tether-elements-to-each-other-with-css-anchor-positioning/&quot; rel=&quot;noopener noreferrer&quot;&gt;the introductory article&lt;/a&gt; by &lt;a href=&quot;https://jhey.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;Jhey Tompson&lt;/a&gt;. However, many of its details are outdated, like the change from anchor-scroll to anchor-default and several other aspects.&lt;/p&gt;&lt;p&gt;My goal today is to talk about what anchor positioning brings to the table, not to get lost in the particularities of the current implementation. I will not include many demos and examples of code in this post but will link to a list of experiments for you to explore in the end.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-concepts&quot;&gt;The Concepts&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#the-concepts&quot; aria-labelledby=&quot;the-concepts&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In a general sense, anchor positioning is &lt;em&gt;an addition&lt;/em&gt; to the existing absolute and fixed positioning (I’ll use “absolute” for both in the future to simplify things). It augments them by providing the superpower of knowing the positions and dimensions of other elements.&lt;/p&gt;&lt;p&gt;By itself, absolute positioning is &lt;em&gt;absolute&lt;/em&gt;: you give it coordinates that are based on its positioning context (closest positioned ancestor or its initial containing block). That’s one of the two things our element knows about. The other is a &lt;a href=&quot;https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width&quot; rel=&quot;noopener noreferrer&quot;&gt;“hypothetical box”&lt;/a&gt; — the initial position of the element if an inset property was not set, which might be a powerful way to handle absolute positioning but a fragile one.&lt;/p&gt;&lt;p&gt;And that’s it. Every so often, this is enough, but for many cases where we want an element to be visually attached to something, these limitations result in either us adding “magic” numbers or a lot of JavaScript.&lt;/p&gt;&lt;p&gt;Anchor positioning helps us by providing the information we need — and sometimes more.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;connecting-elements&quot;&gt;Connecting Elements&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#connecting-elements&quot; aria-labelledby=&quot;connecting-elements&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Anchor positioning does this by allowing us to explicitly &lt;strong&gt;connect&lt;/strong&gt; an absolutely-positioned element to another element.&lt;/p&gt;&lt;p&gt;We do this in two steps in CSS:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We give our anchor element the &lt;code&gt;anchor-name&lt;/code&gt; property, which can contain one or more &lt;a href=&quot;https://drafts.csswg.org/css-values-4/#typedef-dashed-ident&quot; rel=&quot;noopener noreferrer&quot;&gt;dashed identifiers&lt;/a&gt;, for example, &lt;code&gt;anchor-name: --tooltip-context&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;At the same time, we use this name on our absolutely-positioned element, mentioning it in the &lt;code&gt;anchor-default&lt;/code&gt; property, or inside the &lt;code&gt;anchor()&lt;/code&gt; or &lt;code&gt;anchor-size()&lt;/code&gt; functions.&lt;/li&gt;&lt;/ol&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Alternatively, we could use the &lt;code&gt;anchor&lt;/code&gt; attribute in HTML, provided by the &lt;a href=&quot;https://open-ui.org/components/popover.research.explainer/#anchoring&quot; rel=&quot;noopener noreferrer&quot;&gt;Popover API&lt;/a&gt;, which will be assigned to the &lt;code&gt;anchor-default&lt;/code&gt; as the implicit anchor. &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/&quot;&gt;Learn more about the Popover API on day 1&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;When we do this, we connect our anchored element with its anchor, providing the coordinates and dimensions to be used as the base for positioning. That means our elements now do not live in isolation — they are &lt;em&gt;connected&lt;/em&gt;, and a change in the size or position of one would result in the corresponding change in another.&lt;/p&gt;&lt;p&gt;In the below example, we can see how when we click on the button, the popover appears attached to it.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;WNPKVer&quot; data-user=&quot;kizu&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kizu/pen/WNPKVer&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;We’re not limited by connecting one element to one another. We can have a many-to-many relationship: multiple elements can connect to one anchor, and one element can use the information from multiple anchors, including inside calculations!&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;There are limitations and nuances over when we can attach our element to an anchor, but these details are out of the scope of this article. Things could change or be updated, but if you’re curious, you can read the &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/#acceptable-anchor-element&quot; rel=&quot;noopener noreferrer&quot;&gt;“acceptable anchor element”&lt;/a&gt; section of the specification.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;The demo above, for example, uses multiple anchors to position the arrow of a popover. You might notice that the popover itself is centered relative to the button, but the arrow has two attachment points: the popover itself and a snowflake inside the button.&lt;/p&gt;&lt;p&gt;Speaking of centering behavior, this is the most complex part of this demo. The code for it might look unappealing:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[popover]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;inset-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;anchor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; -&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0% - &lt;span class=&quot;token function&quot;&gt;anchor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - &lt;span class=&quot;token function&quot;&gt;anchor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;margin-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Try wrapping your head around how this is calculated! This code is an adapted version of what was in the specs initially, but thankfully, we will have better ways of handling this in the works.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;area-based-positioning&quot;&gt;Area-based Positioning&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#area-based-positioning&quot; aria-labelledby=&quot;area-based-positioning&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This summer, &lt;a href=&quot;https://fantasai.inkedblade.net/&quot; rel=&quot;noopener noreferrer&quot;&gt;Elika J. Etemad&lt;/a&gt; and &lt;a href=&quot;https://jensimmons.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Jen Simmons&lt;/a&gt; from Apple, with the help of &lt;a href=&quot;https://www.miriamsuzanne.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Miriam Suzanne&lt;/a&gt;, provided their alternative exploration of anchor positioning. You can read &lt;a href=&quot;https://fantasai.inkedblade.net/style/specs/css-anchor-exploration/&quot; rel=&quot;noopener noreferrer&quot;&gt;their original exploration&lt;/a&gt; and go through &lt;a href=&quot;https://www.icloud.com/keynote/0f5UxcimbeDm24dK6S_Of2YOw#Anchor_positioning_presentation_to_CSSWG&quot; rel=&quot;noopener noreferrer&quot;&gt;the slides&lt;/a&gt; they showed at the CSSWG face-to-face meeting.&lt;/p&gt;&lt;p&gt;Many things were proposed in the exploration, but the first thing that found its place in the revised specifications is &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/#inset-area&quot; rel=&quot;noopener noreferrer&quot;&gt;the inset-area property&lt;/a&gt; — the idea of positioning things using a grid-like syntax.&lt;/p&gt;&lt;p&gt;As I demonstrated in the above example, we had to use overcomplicated calculations to center things properly. In the future, we will have &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/#anchor-center&quot; rel=&quot;noopener noreferrer&quot;&gt;an anchor-center value&lt;/a&gt; for self-alignment properties, but even then, we will have to rely on specifying the inset properties, which might be cumbersome.&lt;/p&gt;&lt;p&gt;The way &lt;code&gt;inset-area&lt;/code&gt; would help with this is by allowing us to tell the anchored element to be positioned in a specific area of a 3×3 grid, which is formed around its positioning context and its anchor.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/884b442c-2239-49fe-af71-2c789ebdfce4_inset-area-example.png?auto=compress,format&quot; alt=&quot;An illustration showing a 3 by 3 grid. There is a yellow, rounded block with the “anchor” text in the middle of this grid, and a rounded magenta block with the text “1st choice” takes two cells horizontally and is placed in the top-left corner. Around the grid there are multiple headings which label each row and column. On top the columns are: “start”, “center” and “end” (in green). On the bottom the same columns are labeled as “left”, “center” and “right” (in blue). On the left the rows are: “start”, “center” and “end” (in green), with the corresponding labels on the other side “top”, “center” and “bottom” (in blue). Both on the top and on the left of the illustration, there are dark blue lines that span the whole width and height of the grid, with the label “all” near them, in dark blue color.&quot; /&gt;&lt;figcaption&gt;An example of &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/#propdef-inset-area&quot; rel=&quot;noopener noreferrer&quot;&gt;inset-area: start center / top&lt;/a&gt; positioning. This illustration first appeared in &lt;a href=&quot;https://www.icloud.com/keynote/0f5UxcimbeDm24dK6S_Of2YOw#Anchor_positioning_presentation_to_CSSWG&quot; rel=&quot;noopener noreferrer&quot;&gt;the slides&lt;/a&gt;, now present in the specs.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;This is intended to provide a simple way to handle the most common cases for popovers and tooltips and will come with several built-in mechanisms for how the alignment will be handled.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Unlike &lt;code&gt;anchor()&lt;/code&gt;, &lt;code&gt;inset-area&lt;/code&gt; can use only one anchor, and for more complicated cases the more granular inset properties would be a better choice. &lt;/p&gt;&lt;/aside&gt;&lt;p&gt;I did file &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/9662&quot; rel=&quot;noopener noreferrer&quot;&gt;a CSSWG issue&lt;/a&gt; suggesting that we could use another anchor as a way to define our “containing block” that is used for &lt;code&gt;inset-area&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;While I was writing this article, the Chromium team &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=1477314&quot; rel=&quot;noopener noreferrer&quot;&gt;started working&lt;/a&gt; on the &lt;code&gt;inset-area&lt;/code&gt; prototype, and right now, we can play with it in Chrome Canary.&lt;/p&gt;&lt;p&gt;However, not all the moving pieces are in place that could help us see how useful this method will be. One of &lt;code&gt;inset-area&lt;/code&gt;’s prominent features is how it will work with &lt;a href=&quot;https://drafts.csswg.org/css-align-3/#self-alignment-properties&quot; rel=&quot;noopener noreferrer&quot;&gt;self-alignment properties&lt;/a&gt;, and this interaction is not yet in the prototype.&lt;/p&gt;&lt;p&gt;A few months back, after Apple presented their ideas, I created a prototype using existing anchor positioning in Chrome Canary. It used overly complicated CSS based on &lt;a href=&quot;https://kizu.dev/cyclic-toggles/&quot; rel=&quot;noopener noreferrer&quot;&gt;cyclic toggles&lt;/a&gt; as an attempt to test this syntax alongside the self-alignment and the potential &lt;code&gt;::tether&lt;/code&gt; pseudo-element.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;zYMmVJd&quot; data-user=&quot;kizu&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/kizu/pen/zYMmVJd&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;It does not do everything right and might differ from what we have in Chrome Canary for &lt;code&gt;inset-area&lt;/code&gt;. Nevertheless, I got enough insights from it, and I invite you to play with it and make your own observations! (Don’t look into the source — it is messy. I warned you!)&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;position-fallbacks&quot;&gt;Position Fallbacks&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#position-fallbacks&quot; aria-labelledby=&quot;position-fallbacks&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Another big aspect of anchor positioning is how it will handle how our anchored elements behave when they go beyond their scrollports.&lt;/p&gt;&lt;p&gt;There are multiple ways to achieve this in the current Canary implementation, but the specification is in motion, and it is certain that things will change, so I won’t describe the way it works now.&lt;/p&gt;&lt;p&gt;The idea that will stay: we will have a way to define how things will look when there is no space for an element, like flipping the popover to a different place.&lt;/p&gt;&lt;p&gt;In this screen recording of the demo in action, the popover changes its position when there is not enough space. The way the inline inset is set up also allows it to shrink to remain centered when located at the edge of the screen.&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/anchor-positioning-button-light.mp4&quot;&gt;&lt;/video&gt;&lt;p&gt;This is a video from a &lt;a href=&quot;https://codepen.io/kizu/pen/WNPKVer&quot; rel=&quot;noopener noreferrer&quot;&gt;demo I did show before&lt;/a&gt;, where I used the current implementation and some hacks to achieve the desired behavior. Hopefully, the final specification allows us to do things without hacks!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;accessibility-considerations&quot;&gt;Accessibility Considerations&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#accessibility-considerations&quot; aria-labelledby=&quot;accessibility-considerations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Apart from the anchor positioning not being ready for production in any way, one thing is worth mentioning: anchor positioning is used for &lt;em&gt;connecting&lt;/em&gt; things with each other. &lt;/p&gt;&lt;p&gt;When using the &lt;code&gt;popover&lt;/code&gt; attribute, the connection would be established, however, with an &lt;code&gt;anchor&lt;/code&gt; attribute by itself, and when done in CSS via &lt;code&gt;anchor-name&lt;/code&gt;, this connection is purely &lt;em&gt;visual&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;That means that while it &lt;em&gt;is&lt;/em&gt; possible to connect elements that are located in different places on the page, anchor positioning could lead to the content not being accessible: visually, the content would be located together, but for keyboard navigation or any assistive technologies the pieces will be disjointed.&lt;/p&gt;&lt;p&gt;Again, the specs and its prototype implementation are in motion, and nothing is certain yet. We need to explore what anchor positioning could mean for accessibility in the future and participate in the discussions about that. &lt;/p&gt;&lt;p&gt;For example, I created an issue in CSSWG, where I proposed to automatically adjust the elements&amp;#39; logical (tab and reading) order when they’re connected via anchor positioning. It would be great if this could be handled from the get-go, and if you have anything to add — add your voice!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-links-and-experiments&quot;&gt;Additional Links and Experiments&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/anchor-positioning/#additional-links-and-experiments&quot; aria-labelledby=&quot;additional-links-and-experiments&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There were many aspects of anchor positioning that I did not cover in this post: &lt;code&gt;anchor-size()&lt;/code&gt; (which &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/8586&quot; rel=&quot;noopener noreferrer&quot;&gt;I wish could be used for non-sizing properties&lt;/a&gt;), &lt;a href=&quot;https://drafts.csswg.org/css-anchor-position-1/#scroll&quot; rel=&quot;noopener noreferrer&quot;&gt;how to take the scroll into account&lt;/a&gt;, and other aspects of the features I covered or mentioned (for example, the nuances of how fixed positioning works when anchored). This is a complex spec!&lt;/p&gt;&lt;p&gt;In closing, I will list several articles and demos I recommend you check out if you are keen to learn more and see various use cases where anchor positioning can help. There are plenty of things we could do with it!&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/tether-elements-to-each-other-with-css-anchor-positioning/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Tether elements to each other with CSS anchor positioning”&lt;/a&gt; — the already mentioned article by &lt;a href=&quot;https://jhey.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;Jhey Tompson&lt;/a&gt; (many demos in this one!)&lt;/li&gt;&lt;li&gt;My first article about anchor positioning: &lt;a href=&quot;https://kizu.dev/anchor-positioning-experiments/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Future CSS: Anchor Positioning”&lt;/a&gt; — contains many use cases outside the more common tooltips and popovers.&lt;/li&gt;&lt;li&gt;My second, recent article: &lt;a href=&quot;https://kizu.dev/shrinkwrap-problem/&quot; rel=&quot;noopener noreferrer&quot;&gt;“The Shrinkwrap Problem: Possible Future Solutions”&lt;/a&gt; — about how one aspect of anchor positioning can help partially solve one of the oldest CSS problems.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://hidde.blog/positioning-anchored-popovers/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Positioning anchored popovers”&lt;/a&gt; by &lt;a href=&quot;https://hidde.blog/&quot; rel=&quot;noopener noreferrer&quot;&gt;Hidde de Vries&lt;/a&gt; — an article exploring different ways we can anchor things when using the Popover API, including anchor positioning.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://una.im/radial-menu/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Building a no-JS radial menu with CSS trigonometry, popover, and anchor positioning”&lt;/a&gt; — an article by &lt;a href=&quot;https://una.im/&quot; rel=&quot;noopener noreferrer&quot;&gt;Una Kravets&lt;/a&gt; in which she builds a radial menu by using Popover API and anchor positioning.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://meyerweb.com/eric/thoughts/2023/09/12/nuclear-anchored-sidenotes/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Nuclear Anchored Sidenotes”&lt;/a&gt; by &lt;a href=&quot;https://meyerweb.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Eric Meyer&lt;/a&gt; — an article exploring one of the more interesting use cases for anchor positioning.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you’re curious how things evolved, you can look at all the explainers that were done:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The most recent &lt;a href=&quot;https://xiaochengh.github.io/Explainers/css-anchor-position/explainer.html&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Anchor Positioning Explainer&lt;/a&gt; by &lt;a href=&quot;https://github.com/xiaochengh&quot; rel=&quot;noopener noreferrer&quot;&gt;Xiaocheng Hu&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;An outdated &lt;a href=&quot;https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/CSSAnchoredPositioning/explainer.md&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Anchored Positioning&lt;/a&gt; explainer by the Microsoft Edge team.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://melanie-richards.com/blog/anchor-pos-use-cases/&quot; rel=&quot;noopener noreferrer&quot;&gt;“Call for web dev feedback: anchored positioning use cases + requirements”&lt;/a&gt; by &lt;a href=&quot;https://melanie-richards.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Melanie Richards&lt;/a&gt;, in which she asks for dev feedback regarding the above proposal. A &lt;a href=&quot;https://github.com/openui/open-ui/issues/357&quot; rel=&quot;noopener noreferrer&quot;&gt;linked issue&lt;/a&gt; with the gathered feedback and use cases is also a very nice collection of things to think about in the context of anchor positioning.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gist.github.com/bfgeek/60d4f57092eadcda0d4f32a8eb23b4c8&quot; rel=&quot;noopener noreferrer&quot;&gt;The initial exploration&lt;/a&gt; by &lt;a href=&quot;https://github.com/bfgeek&quot; rel=&quot;noopener noreferrer&quot;&gt;Ian Kilpatrick&lt;/a&gt; and &lt;a href=&quot;https://xanthir.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Tab Atkins-Bittner&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://kizu.dev/&quot;&gt;Roman Komarov&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/92e4d123-032a-46a8-9a9b-b25fecdbba95_roman.jpg?auto=compress,format&amp;rect=0,0,1175,1175&amp;w=150&amp;h=150&quot; alt=&quot;Roman Komarov&quot; /&gt;
  &lt;p&gt;Roman have been writing CSS as a full-time job for more than 16 years, always experimenting and pushing the boundaries of what is possible, trying the new specifications and giving his feedback as an author.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Roman selected &lt;strong&gt;&lt;a href=&quot;https://queerjs.com/&quot;&gt;QueerJS&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://queerjs.com/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/9ea8469a-f677-4579-a2f8-8de4851929c8_queerjs.jpeg?auto=compress,format&quot; alt=&quot;QueerJS&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;QueerJS is a meetup series where everyone is encouraged to attend and support the speakers and the idea. If you&#39;re queer and want to speak, this meetup is for you! It exists to give you a voice and to make a safe space where everyone is welcome.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Popover API</title>
    <link href="https://12daysofweb.dev/2023/popover-api/"/>
    <updated>2023-12-13T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2023/popover-api/</id>
    <content type="html">



&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-are-popovers&quot;&gt;What are Popovers?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#what-are-popovers&quot; aria-labelledby=&quot;what-are-popovers&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The Popover API is a new feature of browsers to help create overlapping user interface elements and avoid common issues related to &lt;code&gt;z-index&lt;/code&gt; stacking, dismissals, poorly implemented accessibility, and more. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;brought-to-us-by-open-ui&quot;&gt;Brought to us by Open UI&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#brought-to-us-by-open-ui&quot; aria-labelledby=&quot;brought-to-us-by-open-ui&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The Popovers API is a browser addition &lt;a href=&quot;https://open-ui.org/components/popover.research.explainer/&quot; rel=&quot;noopener noreferrer&quot;&gt;proposed by Open UI&lt;/a&gt;, a W3C community group that has set out to define and extend the capabilities of built-in web components. &lt;/p&gt;&lt;p&gt;Open UI has a clear set of goals for Popovers, including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Accessible by default&lt;/li&gt;&lt;li&gt;Easily styled and animated&lt;/li&gt;&lt;li&gt;Built-in light dismissals, such as pressing the &lt;code&gt;Esc&lt;/code&gt; key&lt;/li&gt;&lt;li&gt;An easy way to move any element to the &lt;code&gt;#top-layer&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Most common usage will not require JavaScript&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;how-to-use-popovers&quot;&gt;How to use Popovers&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#how-to-use-popovers&quot; aria-labelledby=&quot;how-to-use-popovers&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Popovers were designed for easy implementation and can be used without needing to reach for JavaScript. To create a popover element, all that is needed is to add the &lt;code&gt;popover&lt;/code&gt; attribute to the element that will be overlapping other elements within the UI.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-popover&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;popover&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This is a popover!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The element will be hidden automatically, only becoming visible once toggled open. &lt;/p&gt;&lt;p&gt;Now, let’s create a button to toggle the popover. On the button, add the &lt;code&gt;popovertarget&lt;/code&gt; attribute and supply the &lt;code&gt;id&lt;/code&gt; of the popover element. Another necessary attribute is the &lt;code&gt;popovertargetaction&lt;/code&gt; attribute, which will tell the browser what to do with the popover.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;popovertarget&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-popover&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;popovertargetaction&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  Toggle Popover&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-popover&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;popover&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This is a popover!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;popovertargetaction&lt;/code&gt; action has three possible actions that can be performed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;toggle&lt;/code&gt; - toggles the popover between an open and closed state.&lt;/li&gt;&lt;li&gt;&lt;code&gt;show&lt;/code&gt; - sets the popover to an open state.&lt;/li&gt;&lt;li&gt;&lt;code&gt;hide&lt;/code&gt; - sets the popover to a closed state.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;javascript-implementation&quot;&gt;JavaScript Implementation&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#javascript-implementation&quot; aria-labelledby=&quot;javascript-implementation&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Popovers can also be controlled through JavaScript with the addition of new methods that can be used on popover elements.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;showPopover()&lt;/code&gt; - sets the popover to an open state.&lt;/li&gt;&lt;li&gt;&lt;code&gt;hidePopover()&lt;/code&gt; - sets the popover to a closed state.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Actions related to the popover state can be run by listening for the &lt;code&gt;onpopovershow&lt;/code&gt; and &lt;code&gt;onpopoverhide&lt;/code&gt; events. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;styling-popovers&quot;&gt;Styling Popovers&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#styling-popovers&quot; aria-labelledby=&quot;styling-popovers&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Popovers can be styled with CSS like any other element by targeting the popover’s &lt;code&gt;class&lt;/code&gt; or &lt;code&gt;id&lt;/code&gt;, however, popovers can also be targetted by utilizing the bracketed attribute selector &lt;code&gt;[popover]&lt;/code&gt;. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[popover]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two new pseudoselectors can be helpful in styling popovers:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;:popover-open&lt;/code&gt; - applies styling only when a popover is in an open state (great for animations!)&lt;/li&gt;&lt;li&gt;&lt;code&gt;::backdrop&lt;/code&gt; - enables styling of the popover’s backdrop.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;accessible-by-default&quot;&gt;Accessible by default&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#accessible-by-default&quot; aria-labelledby=&quot;accessible-by-default&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Popovers were created with accessibility in mind, with a few accessibility features included out-of-box:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Any element can become a popover, which carries over element semantics to the &lt;code&gt;#top-layer&lt;/code&gt; as well.&lt;/li&gt;&lt;li&gt;When popover elements are open, they become the next focusable element in the &lt;code&gt;tabindex&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Users can close popovers by pressing the &lt;code&gt;Esc&lt;/code&gt; key on the keyboard, as well as clicking outside the popover to dismiss.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;popover-example&quot;&gt;Popover Example&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#popover-example&quot; aria-labelledby=&quot;popover-example&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Here is a demo using Popovers to create a drawer component&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;NWoBXBg&quot; data-user=&quot;mrtrimble&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/mrtrimble/pen/NWoBXBg&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;This demo is taking advantage of all the main features of the Popover API, including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;No JavaScript is utilized to create the drawer toggle action.&lt;/li&gt;&lt;li&gt;The drawer is placed in the &lt;code&gt;#top-layer&lt;/code&gt; which prevents any issues with &lt;code&gt;z-index&lt;/code&gt; stacking.&lt;/li&gt;&lt;li&gt;The Popover drawer is styled using &lt;code&gt;[popover]&lt;/code&gt; attribute selector, and utilizing the &lt;code&gt;::backdrop&lt;/code&gt; pseudo element and &lt;code&gt;:popover-open&lt;/code&gt; pseudo selector for animations.&lt;/li&gt;&lt;li&gt;The drawer can be closed by clicking the &amp;quot;Close&amp;quot; button within the drawer, by pressing the &lt;code&gt;Esc&lt;/code&gt; key on the keyboard, or by clicking outside the drawer.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;browser-support&quot;&gt;Browser Support&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#browser-support&quot; aria-labelledby=&quot;browser-support&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Popovers are a fairly new concept that is &lt;a href=&quot;https://caniuse.com/mdn-api_htmlelement_popover&quot; rel=&quot;noopener noreferrer&quot;&gt;being adopted by browsers&lt;/a&gt;. Chrome 114 was the first browser to introduce Popovers and recently was added to Safari in version 17. Firefox has yet to implement Popovers fully, however, they can be enabled via a feature flag.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;more-resources-on-popovers&quot;&gt;More resources on Popovers&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2023/popover-api/#more-resources-on-popovers&quot; aria-labelledby=&quot;more-resources-on-popovers&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For further reading on the Popover API, check out the following links:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://open-ui.org/components/popover.research.explainer/&quot; rel=&quot;noopener noreferrer&quot;&gt;Open UI Explainer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Hidde de Vries post on &lt;a href=&quot;https://hidde.blog/dialog-modal-popover-differences/&quot; rel=&quot;noopener noreferrer&quot;&gt;differences between `&amp;lt;dialog&amp;gt;` and Popovers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Adrian Roselli wrote a &lt;a href=&quot;https://adrianroselli.com/2023/05/brief-note-on-popovers-with-dialogs.html&quot; rel=&quot;noopener noreferrer&quot;&gt;brief note on using Popovers and Dialogs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Popover_API&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN page on Popovers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute&quot; rel=&quot;noopener noreferrer&quot;&gt;HTML Spec on Popovers&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://www.ryantrimble.com/&quot;&gt;Ryan Trimble&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/f8a998be-1a81-46d7-a87f-a01a2b5ff0ec_ryan.jpeg?auto=compress,format&amp;rect=0,0,400,400&amp;w=150&amp;h=150&quot; alt=&quot;Ryan Trimble&quot; /&gt;
  &lt;p&gt;Ryan is a web developer based in Central PA who is passionate about coding and making people happy.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Ryan selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS Subgrid</title>
    <link href="https://12daysofweb.dev/2022/css-subgrid/"/>
    <updated>2022-12-24T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/css-subgrid/</id>
    <content type="html">



&lt;p&gt;The &lt;code&gt;subgrid&lt;/code&gt; value for &lt;code&gt;grid-template-rows&lt;/code&gt; and &lt;code&gt;grid-template-columns&lt;/code&gt; is now &lt;a href=&quot;https://caniuse.com/css-subgrid&quot; rel=&quot;noopener noreferrer&quot;&gt;supported in Firefox and Safari 16+&lt;/a&gt;, and coming soon to Chrome. In this article, you’ll learn the ways that this feature makes grid layout even more powerful. &lt;/p&gt;&lt;p&gt;All of the examples in this article can be viewed with subgrid working in Firefox or Safari 16+, except for the final example.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;it-doesnt-add-a-whole-lot-more-complexity&quot;&gt;It doesn’t add a whole lot more complexity&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#it-doesnt-add-a-whole-lot-more-complexity&quot; aria-labelledby=&quot;it-doesnt-add-a-whole-lot-more-complexity&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Using subgrid means that instead of creating a track listing as a value for &lt;code&gt;grid-template-columns&lt;/code&gt; and &lt;code&gt;grid-template-rows&lt;/code&gt;, you use the keyword &lt;code&gt;subgrid&lt;/code&gt;. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;There are no new properties or values to learn, just a decision to make—do you want your nested grid to have its own row and/or column definition, or to use the one from the parent?&lt;/p&gt;&lt;p&gt;In the first example, I have a nested grid that is creating its own tracks for rows and columns. These tracks are independent, and so will not line up with the tracks on the parent grid.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ZERZEJB&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/ZERZEJB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;The second example replaces the track listing for &lt;code&gt;grid-template-columns&lt;/code&gt; with the keyword &lt;code&gt;subgrid&lt;/code&gt;. The column tracks of the nested grid now line up with those on the parent.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;xxzeGOG&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/xxzeGOG&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-have-subgrids-in-your-subgrids&quot;&gt;You can have subgrids in your subgrids&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-can-have-subgrids-in-your-subgrids&quot; aria-labelledby=&quot;you-can-have-subgrids-in-your-subgrids&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As long as each parent is a grid itself, you can keep inheriting subgrids down into children.&lt;/p&gt;&lt;p&gt;The following example shows three grids, each nested inside the other, and inheriting the tracks of their parent. The child items indicate which grid is their parent. Using Firefox DevTools to highlight each grid, highlighting the outer grid shows how the children grids and grid items all align to that grid.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/b9f7c4bf-6fbd-4cf6-9dad-478b980acc63_subgrids-in-subgrids.png?auto=compress,format&quot; alt=&quot;A subgrid layout with Firefox DevTools subgrid overlay reveals a parent 9-column grid and two nested subgrids with elements aligning to the parent grid, one child in the second parent column, the next child in the third parent column.&quot; /&gt;&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ExRJjWa&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/ExRJjWa&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-dont-need-to-have-a-subgrid-in-both-dimensions&quot;&gt;You don’t need to have a subgrid in both dimensions&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-dont-need-to-have-a-subgrid-in-both-dimensions&quot; aria-labelledby=&quot;you-dont-need-to-have-a-subgrid-in-both-dimensions&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When subgrid was discussed in the CSS Working Group, there was a suggestion that it should be locked to both rows and columns. This would have meant there was no implicit grid in either dimension, and subgrid would only be useful if you knew exactly how many grid cells you needed in the subgrid.&lt;/p&gt;&lt;p&gt;In the next example, I have created a subgrid on columns to ensure items in the nested grid can align with items directly inside the parent grid. However, I am using the implicit grid for rows, as I may have any number of items.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;GRGLpKB&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/GRGLpKB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;subgrid-can-help-with-situations-where-you-need-to-target-the-end-line-of-the-implicit-grid&quot;&gt;Subgrid can help with situations where you need to target the end line of the implicit grid&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#subgrid-can-help-with-situations-where-you-need-to-target-the-end-line-of-the-implicit-grid&quot; aria-labelledby=&quot;subgrid-can-help-with-situations-where-you-need-to-target-the-end-line-of-the-implicit-grid&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The previous example demonstrates another useful pattern enabled by subgrid. It’s possible to target the end line of the explicit grid using line &lt;code&gt;-1&lt;/code&gt;. Unfortunately, this doesn’t work to target the end line of an implicit grid.&lt;/p&gt;&lt;p&gt;By nesting repeating items in a container, they all go into one row on the parent. This means you can have the full height column shown in the previous example without needing to know how many lines of items are created implicitly.&lt;/p&gt;&lt;p&gt;If you inspect the previous example using DevTools, you can see how the subgridded items create implicit rows. As the item on the left is in the parent grid, it is in the same row as all of the items and therefore can become as tall as is needed to align with the implicit rows.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/c93d8e36-ddec-494a-b57d-0de3040901ff_subgrid-implicit-rows.png?auto=compress,format&quot; alt=&quot;The parent grid provides 4 columns. A subgrid spans column 2-4 in the parent grid, and creates it&amp;#39;s own 3x4 grid. An item in the first parent grid column is able to visually span the height of the subgrid items.&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-align-things-using-the-line-names-of-the-parent-grid&quot;&gt;You can align things using the line names of the parent grid&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-can-align-things-using-the-line-names-of-the-parent-grid&quot; aria-labelledby=&quot;you-can-align-things-using-the-line-names-of-the-parent-grid&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If your parent grid has named lines, these are accessible from the child. In the following example, lines on the parent grid are named &lt;code&gt;a&lt;/code&gt; through &lt;code&gt;e&lt;/code&gt;. The subgrid and a child of that subgrid are then placed using these named lines. This technique is useful, as it saves keeping track of what line number things are. You can set up names on the parent and know that by placing an item starting at that line it will always align with other things starting on that line.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;dyKLYRK&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/dyKLYRK&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-add-line-names-to-the-subgrid&quot;&gt;You can add line names to the subgrid&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-can-add-line-names-to-the-subgrid&quot; aria-labelledby=&quot;you-can-add-line-names-to-the-subgrid&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Can’t get enough line names? You can add names to the lines within the subgrid. Granted, the syntax is a bit unusual, because we don’t have a track listing to put the line names into. Instead, you add the names after the &lt;code&gt;subgrid&lt;/code&gt; keyword.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.subgrid&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  display&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; subgrid [line1] [line2] [line3]&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These names will be added to any other names the line has, as a line can have multiple names. You can then reference it using any of the names assigned.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;GRGLYeQ&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/GRGLYeQ&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-use-implicitly-named-areas-from-inherited-lines-in-your-main-grid-and-subgrid&quot;&gt;You can use implicitly named areas from inherited lines in your main grid and subgrid&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-can-use-implicitly-named-areas-from-inherited-lines-in-your-main-grid-and-subgrid&quot; aria-labelledby=&quot;you-can-use-implicitly-named-areas-from-inherited-lines-in-your-main-grid-and-subgrid&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When you name lines with the suffix &lt;code&gt;-start&lt;/code&gt; and &lt;code&gt;-end&lt;/code&gt;, you get a named area of the main name used. As lines are inherited so are these named areas. In the following example, I have named lines &lt;code&gt;main-star&lt;/code&gt;t and &lt;code&gt;main-end&lt;/code&gt; and &lt;code&gt;col-start&lt;/code&gt; and &lt;code&gt;col-end&lt;/code&gt;. This gives me a wide column named &lt;code&gt;main&lt;/code&gt;, and a narrow column named &lt;code&gt;col&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;I place the article into &lt;code&gt;grid-column: main&lt;/code&gt;, and then make it a subgrid. I can then place the contents of the article into the narrow column with &lt;code&gt;grid-column: col&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;bGKJQdz&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/bGKJQdz&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-subgrid-can-have-different-sized-gaps-to-its-parent&quot;&gt;The subgrid can have different-sized gaps to its parent&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#the-subgrid-can-have-different-sized-gaps-to-its-parent&quot; aria-labelledby=&quot;the-subgrid-can-have-different-sized-gaps-to-its-parent&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;gap&lt;/code&gt; property will inherit into the subgrid so, by default, a subgridded element will have the same size gaps as its parent. If you don’t want that, use the &lt;code&gt;gap&lt;/code&gt; property (or &lt;code&gt;column-gap&lt;/code&gt; or &lt;code&gt;row-gap&lt;/code&gt;) to change it. &lt;/p&gt;&lt;p&gt;In the following example, the parent grid has &lt;code&gt;20px&lt;/code&gt; gaps for rows and columns. In the subgrid, I want just 1 pixel of the background to show through as a gap, so I have changed the &lt;code&gt;gap&lt;/code&gt; on the subgridded card to &lt;code&gt;1px&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;WNyWYxB&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/WNyWYxB&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;you-can-line-up-items-that-are-in-different-subgrids&quot;&gt;You can line up items that are in different subgrids&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#you-can-line-up-items-that-are-in-different-subgrids&quot; aria-labelledby=&quot;you-can-line-up-items-that-are-in-different-subgrids&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Using subgrid for rows means that items nested in separate subgrids, such as the cards in the previous example, are in the same row meaning items inside can align with each other. If I add more content to one of the headings, you can see how all headings in that row get extra space below and remain aligned.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;oNyOQWp&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/oNyOQWp&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;subgrid-can-be-usefully-combined-with-container-queries&quot;&gt;Subgrid can be usefully combined with container queries&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#subgrid-can-be-usefully-combined-with-container-queries&quot; aria-labelledby=&quot;subgrid-can-be-usefully-combined-with-container-queries&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A common pattern is to have a 12-column grid at all breakpoints, and as the viewport becomes smaller, items span more of the columns. At a very narrow viewport width an item might span all 12, on the desktop 3.&lt;/p&gt;&lt;p&gt;Using container queries, you can test to see if the container has enough space, then switch on subgrid so the component can use the tracks it spans across. In the following example, the card spans two column tracks of the parent grid. At narrow widths, the card is not a subgrid, and the image and content display one after the other. &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/cae2a33d-4983-4f47-a9c9-2ce6fe0145f0_subgridcard-narrow.png?auto=compress,format&quot; alt=&quot;A card component placed in the middle two columns of a parent grid does not use subgrid on a narrow viewport and the caption is stacked below the image.&quot; /&gt;&lt;/p&gt;&lt;p&gt;Once there is enough room, the card becomes a subgrid and the image and content display side by side.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/791238d5-05ee-4f6e-a82a-3c2bf80d18c9_subgridcard-wide.png?auto=compress,format&quot; alt=&quot;A card component placed in the middle two columns of a parent grid on a wider viewport uses subgrid and so the image displays in the first column and the caption in the second column.&quot; /&gt;&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;To view this example, you need to use a browser that supports subgrid and container queries. At the time of writing that’s Safari 16+ or Firefox Nightly.&lt;/p&gt;&lt;/aside&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;GRGLwMw&quot; data-user=&quot;rachelandrew&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/rachelandrew/pen/GRGLwMw&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-on-subgrid&quot;&gt;Additional resources on subgrid&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/#additional-resources-on-subgrid&quot; aria-labelledby=&quot;additional-resources-on-subgrid&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With subgrid coming to all engines very soon, it’s a great time to start to play with it and see what other reasons to love subgrid you can come up with. See the following resources for more ideas and help.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Subgrid&quot; rel=&quot;noopener noreferrer&quot;&gt;Subgrid on MDN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2018/07/css-grid-2/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Grid Level 2: Here comes subgrid&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=rmF_iE0lMzw&quot; rel=&quot;noopener noreferrer&quot;&gt;Hello Subgrid! (video)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gridbyexample.com/examples/#css-grid-level-2-examples&quot; rel=&quot;noopener noreferrer&quot;&gt;Subgrid examples on Grid by Example&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://rachelandrew.co.uk/&quot;&gt;Rachel Andrew&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/7358d155-686d-4067-8cdb-949050f65fd5_rachel.jpeg?auto=compress,format&amp;rect=223,40,178,178&amp;w=150&amp;h=150&quot; alt=&quot;Rachel Andrew&quot; /&gt;
  &lt;p&gt;Rachel Andrew works for Google as a technical writer, and content lead for Chrome Web DevRel working on &lt;a href=&quot;https://web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev&lt;/a&gt; and the &lt;a href=&quot;https://developer.chrome.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Chrome Developers site&lt;/a&gt;. She is a front and back-end web developer, author and speaker, author or co-author of 22 books including &lt;a href=&quot;https://abookapart.com/products/the-new-css-layout&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The New CSS Layout&lt;/a&gt; and a regular contributor to a number of publications both on and offline. Rachel is a Member of the CSS Working Group, and can be found posting photos of her cats on Twitter as &lt;a href=&quot;https://twitter.com/rachelandrew&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;@rachelandrew&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Rachel selected &lt;strong&gt;&lt;a href=&quot;https://hollyhedge.org.uk/&quot;&gt;Holly Hedge&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://hollyhedge.org.uk/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/b5c5cead-74a7-433d-9192-44407a24559c_Screen+Shot+2022-12-18+at+3.54.28+PM.png?auto=compress,format&quot; alt=&quot;Holly Hedge&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Holly Hedge is an organization in Rachel&#39;s home town of Bristol. They rescue and rehome unwanted and often poorly treated animals, and do an amazing job finding homes for over 800 animals a year.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS :has()</title>
    <link href="https://12daysofweb.dev/2022/css-has-selector/"/>
    <updated>2022-12-23T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/css-has-selector/</id>
    <content type="html">



&lt;p&gt;Developers have been requesting a parent selector since &lt;a href=&quot;https://api.jquery.com/has/&quot; rel=&quot;noopener noreferrer&quot;&gt;jQuery introduced .has()&lt;/a&gt; in 2007, and it is finally here. At the time of this writing, it is &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=418039&quot; rel=&quot;noopener noreferrer&quot;&gt;behind a flag in Firefox&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:has#browser_compatibility&quot; rel=&quot;noopener noreferrer&quot;&gt;supported in Chrome, Edge, and Safari&lt;/a&gt;.  &lt;/p&gt;&lt;p&gt;The newly supported &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:has&quot; rel=&quot;noopener noreferrer&quot;&gt;`:has()`&lt;/a&gt; is more than just a parent selector; it’s a relational selector. Yes, it can match an ancestor element based on containing a specific descendant, but it can also match antecedent elements based on subsequent content. &lt;/p&gt;&lt;p&gt;The long-supported &lt;code&gt;:nth-last-of-type()&lt;/code&gt; selects an element based on having sibling selectors of the same type. In the following pseudo-code, you can select any &lt;code&gt;h2&lt;/code&gt; that has a later sibling &lt;code&gt;h2&lt;/code&gt;. For example, &lt;code&gt;h2:nth-last-of-type(n+2)&lt;/code&gt; selects the first two &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; elements (the first byline and first subheader).&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”mainheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”byline”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”byline”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;While it has been possible to select previous siblings of the same type with `&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-of-type&quot; rel=&quot;noopener noreferrer&quot;&gt;:nth-last-of-type()&lt;/a&gt;`, &lt;code&gt;:has()&lt;/code&gt; enables selecting previous siblings of &lt;em&gt;any&lt;/em&gt; type. &lt;/p&gt;&lt;p&gt;Given the pseudo-HTML above, how can we target subheaders immediately followed by a byline? &lt;code&gt;h2 + h3&lt;/code&gt; matches the byline, but how do we target only the subheaders that have an adjacent byline?  With &lt;code&gt;h2:has( + h3)&lt;/code&gt;!&lt;/p&gt;&lt;p&gt;Let’s break that down.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;:has()&lt;/code&gt; functional pseudo-class takes a&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Selector_list#relative_selector_list&quot; rel=&quot;noopener noreferrer&quot;&gt; relative selector list&lt;/a&gt; as an argument. Let’s parse those words: functional selector, selector list, and relative selector. We will also cover forgiving selector lists which come into play until &lt;code&gt;:has()&lt;/code&gt; has full browser support.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;functional-pseudo-class&quot;&gt;Functional pseudo-class&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#functional-pseudo-class&quot; aria-labelledby=&quot;functional-pseudo-class&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While there are several selectors with parenthesis, including the linguistic pseudo-classes (&lt;code&gt;:dir()&lt;/code&gt; and &lt;code&gt;:lang()&lt;/code&gt;) and structural pseudo-classes (like &lt;code&gt;:nth-last-of-type()&lt;/code&gt;), there are four selectors considered to be “functional selectors”.&lt;/p&gt;&lt;p&gt;The negation (&lt;code&gt;:not()&lt;/code&gt;), a relational selector (&lt;code&gt;:has()&lt;/code&gt;), the matches-any (&lt;code&gt;:is()&lt;/code&gt;) , and the specificity adjustment (&lt;code&gt;:where()&lt;/code&gt;) pseudo-classes each take a selector list as their argument.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;selector-list&quot;&gt;Selector List&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#selector-list&quot; aria-labelledby=&quot;selector-list&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A selector list is a comma-separated list of selectors.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;It is important to note that if any element in a selector list is invalid, the entire list and associate style block are ignored.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* These are valid */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, #unusedId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yellow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, .unused-class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, undefined-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* These are all invalid */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, #00invalidIdName&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, :fake-pseudo-class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body, *, ::invalid-pseudo-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; purple&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Given the above code, everything on the page will be black. If an &lt;code&gt;id&lt;/code&gt; is a valid id, a &lt;code&gt;class&lt;/code&gt; is a valid class, or a custom element is not defined, and there are no matching elements in the HTML, the CSS doesn’t know or care as there are no matching elements. But pseudo-classes and pseudo-elements can be invalid; &lt;code&gt;:foo &lt;/code&gt;and &lt;code&gt;::-typo-thumb&lt;/code&gt; will make a selector list fail. They, and weird &lt;a href=&quot;https://mathiasbynens.be/notes/css-escapes&quot; rel=&quot;noopener noreferrer&quot;&gt;`id` selectors that aren’t correctly escaped&lt;/a&gt;, will invalidate the entire selector list.&lt;/p&gt;&lt;p&gt;Because the entire selector list and associate code block are ignored if a selector list contains an invalid selector, old code bases have style blocks that are repeated multiple times.&lt;/p&gt;&lt;p&gt;For example, the pseudo-element selector targeting scrollbar and range thumbs are unique to each browser engine; with no browser supporting all of the following:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body,&lt;br /&gt;::-moz-range-thumb,&lt;br /&gt;::-ms-thumb,&lt;br /&gt;::-webkit-scrollbar-thumb&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With the above code, neither the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; nor any scrollbar or range thumb will have a red border in any browser. Because at least one of the prefixed pseudo-elements will be invalid in every browser, the entire block is ignored, and the style block is not applied to anything, not even the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. Because of this, developers have been separating out each prefixed pseudo-element, leading to code similar to the following because normal selector lists are not forgiving.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;::-moz-range-thumb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;::-ms-thumb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;::-webkit-scrollbar-thumb&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;forgiving-selector-list&quot;&gt;Forgiving selector list&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#forgiving-selector-list&quot; aria-labelledby=&quot;forgiving-selector-list&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In a forgiving selector list, each selector is parsed individually. Invalid selectors within the list are simply ignored. The selector lists for &lt;code&gt;:is()&lt;/code&gt;, and &lt;code&gt;:where()&lt;/code&gt; are forgiving. &lt;/p&gt;&lt;p&gt;The above could be written as:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body,&lt;br /&gt;:is( &lt;br /&gt;  ::-moz-range-thumb,&lt;br /&gt;  ::-ms-thumb,&lt;br /&gt;  ::-webkit-scrollbar-thumb&lt;br /&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px solid red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is less verbose while having the same specificity. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Until &lt;code&gt;:has()&lt;/code&gt; is supported in all browsers, when including &lt;code&gt;:has()&lt;/code&gt; with other selectors in a selector list, enclose the selector within an &lt;code&gt;:is()&lt;/code&gt; or &lt;code&gt;:where()&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;h3,&lt;br /&gt;:is(h2:has( + h3))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;specificity&quot;&gt;Specificity&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#specificity&quot; aria-labelledby=&quot;specificity&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;:has()&lt;/code&gt; selector and the other functional pseudo-classes themselves don’t add any &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity&quot; rel=&quot;noopener noreferrer&quot;&gt;specificity&lt;/a&gt; weight to the selector. Rather, except in the case of the specificity-adjustment &lt;code&gt;:where()&lt;/code&gt; pseudo-class, the argument adds the weight. The specificity weights of the&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity#the_is_not_and_has_exceptions&quot; rel=&quot;noopener noreferrer&quot;&gt;`:not()`, `:has()`, and `:is()`&lt;/a&gt; pseudo-classes are the weights of the selector in the selector list with the greatest specificity. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;specificity-of-is&quot;&gt;Specificity of :is()&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#specificity-of-is&quot; aria-labelledby=&quot;specificity-of-is&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Given &lt;code&gt;:is(#fakeId#fakeId#fakeId, body)&lt;/code&gt;, even though body is a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity#selector_weight_categories&quot; rel=&quot;noopener noreferrer&quot;&gt;type&lt;/a&gt; selector, which has low specificity, the specificity weights of the associate property values is the weight of three &lt;code&gt;id&lt;/code&gt; selectors. It matches &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; with a specificity of &lt;code&gt;3-0-0&lt;/code&gt;. The specificity that &lt;code&gt;:not()&lt;/code&gt;, &lt;code&gt;:has()&lt;/code&gt;, and &lt;code&gt;:is()&lt;/code&gt; contribute to the specificity algorithm is the specificity of the selector in the parameter that has the greatest weight.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;specificity-of-where&quot;&gt;Specificity of :where()&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#specificity-of-where&quot; aria-labelledby=&quot;specificity-of-where&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity#the_where_exception&quot; rel=&quot;noopener noreferrer&quot;&gt;`:where()`&lt;/a&gt; pseudo-class is different; it adds no weight to the specificity equation.  &lt;code&gt;:where(#fakeId#fakeId#fakeId, body)&lt;/code&gt; matches &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; with a specificity of &lt;code&gt;0-0-0&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;relative-selector&quot;&gt;Relative selector&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#relative-selector&quot; aria-labelledby=&quot;relative-selector&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Each selector within the &lt;code&gt;:has()&lt;/code&gt; pseudo-class selector list is relational. Relational selectors are selectors that represent elements relative to one another. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;In the case of the &lt;code&gt;:has()&lt;/code&gt; relational selector, the relative selector is in relation to the anchor element, which is the element on which the &lt;code&gt;:has()&lt;/code&gt; is applied. In the case of  &lt;code&gt;h2:has(+h3)&lt;/code&gt;, the anchor is the &lt;code&gt;h2&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;A relative selector is one that starts with a combinator, whether explicit or implied. If there is no explicit combinator, like &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, or &lt;code&gt;+&lt;/code&gt;, the descendant combinator (a space) is implied.&lt;/p&gt;&lt;p&gt;Compare the following selectors:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Given &lt;code&gt;h2:has(+h3)&lt;/code&gt;, or, more legibly, &lt;code&gt;h2:has( + h3)&lt;/code&gt;, the anchor is the &lt;code&gt;h2&lt;/code&gt; and the relational selector is &lt;code&gt;+ h3&lt;/code&gt;. Combined, the selector reads “every h2 that has an adjacent sibling which is an h3”. &lt;/li&gt;&lt;li&gt;Given &lt;code&gt;h2:has(h3)&lt;/code&gt;, the descendant space combinator would be implied as &lt;code&gt;h2:has( h3)&lt;/code&gt;. This selector reads “every h2 that has at least one h3 as a descendant”. &lt;/li&gt;&lt;li&gt;Given &lt;code&gt;h2:has(&amp;gt; h3)&lt;/code&gt; it reads “every h2 which has at least one h3 that is a direct child.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Back to our code example:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”mainheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”byline”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”subheader”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-function&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;”byline”&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The selector &lt;code&gt;main:has(h2 + h3)&lt;/code&gt;, reads “every main that has a descendant h2 which has an h3 as an adjacent sibling”. Associated styles will apply to &lt;code&gt;main&lt;/code&gt;, the anchor, if there is a descendant &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; immediately followed by an &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;. This is an &lt;strong&gt;ancestor&lt;/strong&gt; match. In our code example, the last &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; has an &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; as an adjacent sibling, so this selector selects the ancestor &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For an actual &lt;strong&gt;parent&lt;/strong&gt; selector, (not just an ancestor selector) we use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Child_combinator&quot; rel=&quot;noopener noreferrer&quot;&gt;child combinator (&amp;gt;)&lt;/a&gt;.  &lt;code&gt;main:has(&amp;gt; h2 + h3)&lt;/code&gt; will match as well, as long as the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; is a direct child of &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, which it is. &lt;/p&gt;&lt;p&gt;The parent and ancestor examples had &lt;code&gt;main&lt;/code&gt; as the anchor. If we allow the relationship to be implied, we may not get what we expect. If we include &lt;code&gt;h2:has(h3) &lt;/code&gt;nothing is matched in this scenario, as &lt;code&gt;h3&lt;/code&gt; is not a descendant of the &lt;code&gt;h2&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;The reason &lt;code&gt;:has()&lt;/code&gt; is called a &lt;strong&gt;relational&lt;/strong&gt; selector rather than a parent or ancestor selector is because it can be used for more than just ancestral reasons. To select the &lt;code&gt;h1&lt;/code&gt; only if it is immediately followed by an &lt;code&gt;h2&lt;/code&gt;, we write &lt;code&gt;h1:has(+ h2)&lt;/code&gt;. The &lt;code&gt;+&lt;/code&gt; is the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator&quot; rel=&quot;noopener noreferrer&quot;&gt;adjacent sibling combinator&lt;/a&gt;. &lt;code&gt;* + h2&lt;/code&gt; is a relational selector. &lt;/p&gt;&lt;p&gt;There is also a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_combinator&quot; rel=&quot;noopener noreferrer&quot;&gt;general sibling combinator (~)&lt;/a&gt;. &lt;code&gt;[data-function=&amp;quot;byline&amp;quot;]:has(~ [data-function=&amp;quot;byline&amp;quot;])&lt;/code&gt;, which reads “match any element with the byline function which has a sibling with the byline function”. This will match all the sibling elements with the byline function except the last, regardless of the element type. The last one isn’t matched because it doesn’t have a sibling of that class that comes after it.&lt;/p&gt;&lt;p&gt;Before &lt;code&gt;:has()&lt;/code&gt; was available, while we could select a previous sibling of the same type, selecting a previous sibling element of a different type was not possible.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;logical-operations&quot;&gt;Logical operations&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#logical-operations&quot; aria-labelledby=&quot;logical-operations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;:has()&lt;/code&gt; relational selector can be used to check if one of the multiple features is true or if all the features are true. &lt;/p&gt;&lt;p&gt;When we include multiple selectors in the relative selector list, we can match the anchor element if any of the relational selectors are true. The following matches &lt;code&gt;main&lt;/code&gt; if there are any bylines (a header immediately followed by a next-level header):&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;main:has( &gt; h1 + h2, &gt; h2 + h3, &gt; h3 + h4) p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This reads “style all paragraphs in main if the main has a child &lt;code&gt;h1&lt;/code&gt; immediately followed by an &lt;code&gt;h2&lt;/code&gt;, a child &lt;code&gt;h2&lt;/code&gt; immediately followed by an &lt;code&gt;h3&lt;/code&gt;, or a child &lt;code&gt;h3&lt;/code&gt; immediately followed by an &lt;code&gt;h4&lt;/code&gt;. Including multiple selectors in the list against an anchor is an OR statement.&lt;/p&gt;&lt;p&gt;You can also string multiple relational selectors together to create an AND statement.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;main:has( &gt; h1 + h2):has( &gt; h2 + h3) p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This reads “style all paragraphs in main if the main has a child &lt;code&gt;h1&lt;/code&gt; immediately followed by an &lt;code&gt;h2&lt;/code&gt; AND a child &lt;code&gt;h2&lt;/code&gt; immediately followed by an &lt;code&gt;h3&lt;/code&gt;.&amp;quot; &lt;/p&gt;&lt;p&gt;This codepen includes styles for all these examples&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;ExRqzbe&quot; data-user=&quot;estelle&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/estelle/pen/ExRqzbe&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;usefulness&quot;&gt;Usefulness&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#usefulness&quot; aria-labelledby=&quot;usefulness&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;:has()&lt;/code&gt; selector is more useful than you likely ever imagined. &lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[type=”checkbox”]:required:not(:checked) + label&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* styles to applied to the label of all required checkboxes&lt;br /&gt;  that aren’t checked yet */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With the adjacent sibling combinator, we have been able to style checkbox and radio button labels which generally come after the form control. Now, with &lt;code&gt;:has()&lt;/code&gt;, we can style labels that come before their associated form control.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;p:has(:required:invalid) label,&lt;br /&gt;*:has( &gt; label + :required:invalid) &gt; label&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above provides two selectors that will turn a &lt;code&gt;label&lt;/code&gt; red if the form control is required but not valid, either because the value is invalid or if there is no value entered. The first selector selects the &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; inside a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; if the paragraph contains a form control that is required but not currently valid. When the form control becomes valid, the selector will no longer match, and the label will no longer be red (unless some other CSS made it red). &lt;/p&gt;&lt;p&gt;The second line is more robust. You may not know exactly how the list of form controls is constructed, but that’s OK. You don’t need JavaScript to toggle class names! The second selector styles the label child of any element when a required but invalid form control is the adjacent sibling of that label.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;NyRBeP&quot; data-user=&quot;estelle&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/estelle/pen/NyRBeP&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;The next time you think “let me just add a class to that&amp;quot; or if you ever consider needing to add an inline style, consider whether the element can be targeted with &lt;code&gt;:has()&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;For example, how do you &lt;a href=&quot;https://estelle.github.io/CSS/tables/&quot; rel=&quot;noopener noreferrer&quot;&gt;style all the cells in a &amp;lt;table&amp;gt;&lt;/a&gt; column without adding a class to each &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;lt;td&amp;gt;&lt;/a&gt;? While  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;lt;col&amp;gt;&lt;/a&gt;, the table column element, supports a few styles, there’s no way to style the contents of a cell based on it, or is there?  With &lt;code&gt;:has()&lt;/code&gt;, you can style something in a &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;tfoot&amp;gt;&lt;/code&gt; based on whether a table has a specific attribute or attribute value in the &lt;code&gt;&amp;lt;caption&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;colgroup&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt;. (And really &lt;a href=&quot;https://web.dev/learn/html/tables&quot; rel=&quot;noopener noreferrer&quot;&gt;learning HTML&lt;/a&gt; helps.)&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;table:has(col.right:last-child) tbody tr &gt; :last-child&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  text-align&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the last &lt;code&gt;&amp;lt;col&amp;gt;&lt;/code&gt; in a table has the right class, then the last child of each row in the table body should be aligned right. In this case, we are styling something in one section of a table based on the presence of a class in a different section of the table. This was not possible before.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;wvXNgBv&quot; data-user=&quot;estelle&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/estelle/pen/wvXNgBv&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;This example enabled adding the class of &lt;code&gt;right&lt;/code&gt; or &lt;code&gt;center&lt;/code&gt; to the last six col elements in a &lt;code&gt;colgroup&lt;/code&gt;, styling the last &lt;code&gt;td&lt;/code&gt; or &lt;code&gt;th&lt;/code&gt; in each row in the &lt;code&gt;tbody&lt;/code&gt; based on the class set of the associated but not ancestral col. For years, developers have been complaining about the limited styles that can be set on &lt;code&gt;col&lt;/code&gt; elements; &lt;code&gt;:has()&lt;/code&gt; helps alleviate table styling headaches.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;avoiding-failure&quot;&gt;Avoiding failure&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/#avoiding-failure&quot; aria-labelledby=&quot;avoiding-failure&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For the time being, if you are using &lt;code&gt;:has()&lt;/code&gt; within a selector list, stick the &lt;code&gt;:has()&lt;/code&gt; within a &lt;code&gt;:where()&lt;/code&gt; or &lt;code&gt;:is()&lt;/code&gt; to enable Firefox to ignore the &lt;code&gt;:has()&lt;/code&gt; until it is supported by default (it is currently &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=418039&quot; rel=&quot;noopener noreferrer&quot;&gt;behind a flag&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Note that nesting a &lt;code&gt;:has()&lt;/code&gt; inside another &lt;code&gt;:has()&lt;/code&gt; is not permitted. The &lt;code&gt;:has()&lt;/code&gt; pseudo-class is not supported on pseudo-elements either. For example, &lt;code&gt;::first-line:has(a[href])&lt;/code&gt; will not target a first line containing a link; it is invalid. Similarly, pseudo-elements are not supported within the relative selector list. The specification has allowed for supporting pseudo-elements in the future but has not defined the support of any pseudo-elements as of yet&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://front-end.social/@estelle/&quot;&gt;Estelle Weyl&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/9c442220-a0cc-405f-a259-7de37270dfe2_estelle.png?auto=compress,format&amp;rect=162,0,1280,1280&amp;w=150&amp;h=150&quot; alt=&quot;Estelle Weyl&quot; /&gt;
  &lt;p&gt;Estelle has been building websites since 1999, and documenting the process for other front-end engineers since 2007; reading web specifications so you don&amp;#39;t have to. She is an open source maintainer, technical writer, teacher, and developer advocate, speaking at and organizing conferences, including &lt;a href=&quot;https://perfmattersconf.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;#PerfMattersConf&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Estelle selected &lt;strong&gt;&lt;a href=&quot;https://openwebdocs.org/&quot;&gt;Open Web Docs&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://openwebdocs.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/491fc145-d7e1-406e-9526-381e516e0641_Screen+Shot+2022-12-18+at+10.35.41+AM.png?auto=compress,format&quot; alt=&quot;Open Web Docs&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Open Web Docs supports web platform documentation for the benefit of web developers &amp; designers worldwide.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>2022 CSS Updates</title>
    <link href="https://12daysofweb.dev/2022/2022-css-updates/"/>
    <updated>2022-12-22T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/2022-css-updates/</id>
    <content type="html">



&lt;p&gt;It has been an extra jolly year for the advancement of CSS! &lt;em&gt;Multiple&lt;/em&gt; long-awaited features were integrated into our evergreen browsers (Chrome, Edge, Firefox, and Safari) with a momentum that will stretch into 2023. &lt;/p&gt;&lt;p&gt;Let&amp;#39;s take a quick look under the CSS tree and unwrap the gifts we received this year!&lt;/p&gt;&lt;p&gt;But first, here are three 2022 CSS features already covered in this series:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Cascade layers&lt;/strong&gt; landed after an impressive cross-browser effort in February/March this year, and spec author Miriam Suzanne contributed an &lt;a href=&quot;https://12daysofweb.dev/2022/cascade-layers/&quot;&gt;in-depth guide to cascade layers&lt;/a&gt; on day 5&lt;/li&gt;&lt;li&gt;&lt;strong&gt;:has()&lt;/strong&gt; is considered the &amp;quot;parent&amp;quot; selector, but learn why &lt;a href=&quot;https://12daysofweb.dev/2022/css-has-selector/&quot;&gt;that&amp;#39;s not the whole story&lt;/a&gt; from Estelle Weyl on day 11&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New viewport units&lt;/strong&gt; arrived in November for Chromium to round out the evergreen support, and on day 1, Eric A. Meyer reviewed the &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/&quot;&gt;new dynamic viewport units&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;finesse-element-layout-changes-with-container-queries&quot;&gt;Finesse element layout changes with container queries&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#finesse-element-layout-changes-with-container-queries&quot; aria-labelledby=&quot;finesse-element-layout-changes-with-container-queries&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;CSS container size queries are a way to move beyond media queries that are tied to the viewport and instead will enable us to modify an element&amp;#39;s behavior based on the container it&amp;#39;s within. Anticipate them becoming cross-browser when they are shipped in January in the upcoming &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Experimental_features#container_queries&quot; rel=&quot;noopener noreferrer&quot;&gt;Firefox 109&lt;/a&gt;. With the &lt;a href=&quot;https://github.com/GoogleChromeLabs/container-query-polyfill&quot; rel=&quot;noopener noreferrer&quot;&gt;container queries polyfill&lt;/a&gt;, you can absolutely begin using them today!&lt;/p&gt;&lt;p&gt;I provided a preview of container queries in the 2021 series, but at that time they were still an experimental spec. However, I did update that article when the syntax stabilized later in the year, so go &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;learn how to get started with container queries&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;An upcoming feature often coupled with container queries is for the &lt;strong&gt;range syntax for media queries&lt;/strong&gt;. At this time, it is supported in &lt;a href=&quot;https://caniuse.com/css-media-range-syntax&quot; rel=&quot;noopener noreferrer&quot;&gt;Chrome, Edge, and Firefox, and Safari Technical Preview 160&lt;/a&gt;. It&amp;#39;s also supported via &lt;a href=&quot;https://github.com/GoogleChromeLabs/container-query-polyfill&quot; rel=&quot;noopener noreferrer&quot;&gt;the container queries polyfill&lt;/a&gt; and by build processing tools like &lt;a href=&quot;https://lightningcss.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;LightningCSS&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In 2023, look out for &lt;strong&gt;container style queries&lt;/strong&gt; to stabilize, as well. Ahmad Shadeed has an excellent preview of &lt;a href=&quot;https://ishadeed.com/article/css-container-style-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;ways we&amp;#39;ll be able to use style queries&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;better-control-of-effects-with-individual-transform-properties&quot;&gt;Better control of effects with individual transform properties&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#better-control-of-effects-with-individual-transform-properties&quot; aria-labelledby=&quot;better-control-of-effects-with-individual-transform-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In August, Chromium 104 completed the availability of the &lt;a href=&quot;https://web.dev/css-individual-transform-properties/&quot; rel=&quot;noopener noreferrer&quot;&gt;individual transform properties&lt;/a&gt; of &lt;code&gt;rotate&lt;/code&gt;, &lt;code&gt;scale&lt;/code&gt;, and &lt;code&gt;translate&lt;/code&gt;. This means that when you define a &lt;code&gt;transform&lt;/code&gt; and need to update one of those transform types, you can do so one-off instead of duplicating the rest of the &lt;code&gt;transform&lt;/code&gt; definition, too. &lt;/p&gt;&lt;p&gt;This brings more control for creating transitions and animations, such as to &lt;code&gt;scale&lt;/code&gt; an element with a keyframe animation. Previously you may have used custom properties to alleviate this pain point and achieve similar control, but having separate properties is definitely preferred!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;more-intentional-focus-styles-with-focus-visible&quot;&gt;More intentional focus styles with `:focus-visible`&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#more-intentional-focus-styles-with-focus-visible&quot; aria-labelledby=&quot;more-intentional-focus-styles-with-focus-visible&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In March, Safari 15.4 released the &lt;code&gt;:focus-visible&lt;/code&gt; psuedo-class and shortly after, it became the default element focus behavior used in evergreen browsers. When using  &lt;code&gt;:focus-visible&lt;/code&gt;, based on heuristics, the browser will determine whether to show a &amp;quot;focus ring&amp;quot; - if you don&amp;#39;t supply your own &lt;code&gt;:focus&lt;/code&gt; styles as an override. In practice this means keyboard (tab) interaction on focusable elements like buttons will show a focus ring, but not mouse clicks.&lt;/p&gt;&lt;p&gt;You can review more about how this works and my favorite method to &lt;a href=&quot;https://css-tricks.com/standardizing-focus-styles-with-css-custom-properties/&quot; rel=&quot;noopener noreferrer&quot;&gt;define focus styles with custom properties&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;custom-form-control-colors-with-accent-color&quot;&gt;Custom form control colors with `accent-color`&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#custom-form-control-colors-with-accent-color&quot; aria-labelledby=&quot;custom-form-control-colors-with-accent-color&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Also arriving in Safari 15.4 in March was the &lt;code&gt;accent-color&lt;/code&gt; property. As the writer of a &lt;a href=&quot;https://moderncss.dev/pure-css-custom-styled-radio-buttons/&quot; rel=&quot;noopener noreferrer&quot;&gt;4-part series on customizing form fields&lt;/a&gt;, I can tell you folks are &lt;em&gt;really interested&lt;/em&gt; in this topic!&lt;/p&gt;&lt;p&gt;Using &lt;code&gt;accent-color&lt;/code&gt; allows you to partially colorize four controls: progress, range, checkbox, and radio. Try changing the value of the &lt;code&gt;accent-color&lt;/code&gt; in the following CodePen.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;PoBwprd&quot; data-user=&quot;5t3ph&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/5t3ph/pen/PoBwprd&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;adapt-to-os-darklight-modes-with-color-scheme&quot;&gt;Adapt to OS dark/light modes with `color-scheme`&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#adapt-to-os-darklight-modes-with-color-scheme&quot; aria-labelledby=&quot;adapt-to-os-darklight-modes-with-color-scheme&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;January brought &lt;code&gt;color-scheme&lt;/code&gt; to Firefox to round out support. This property allows you to define which OS color modes your site elements support. It can be set on &lt;code&gt;:root&lt;/code&gt; to affect a page, or on individual elements. It accepts one or two values for the definition, where setting only &amp;quot;light&amp;quot; means you only support a light theme. Using two values, such as setting &amp;quot;light dark&amp;quot;, means your site prefers light mode but will also work with dark mode. This property does not require the use of the &lt;code&gt;prefers-color-scheme&lt;/code&gt; media query to work.&lt;/p&gt;&lt;p&gt;When set on the &lt;code&gt;:root&lt;/code&gt; (and without site overrides to related properties) it will opt-in your entire layout to automatic dark mode when that is the OS option. This includes changing the page background to black and text and form control colors to a lighter color for appropriate contrast. The CodePen demonstrates a page with some text and a few form fields and only the &lt;code&gt;color-scheme&lt;/code&gt; property in use to adapt to light and dark modes.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;zYLxwGo&quot; data-user=&quot;5t3ph&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/5t3ph/pen/zYLxwGo&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;Even if you want to create custom light and dark themes, this property is still beneficial and can be coupled with &lt;code&gt;accent-color&lt;/code&gt; to adapt form controls and achieve a custom feel.&lt;/p&gt;&lt;p&gt;Sara Joy shares &lt;a href=&quot;https://www.htmhell.dev/adventcalendar/2022/19/&quot; rel=&quot;noopener noreferrer&quot;&gt;more about how `color-scheme` works&lt;/a&gt; including the related meta tag and altering it with JavaScript.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;prevent-background-page-scroll-with-overscroll-behavior&quot;&gt;Prevent background page scroll with `overscroll-behavior`&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#prevent-background-page-scroll-with-overscroll-behavior&quot; aria-labelledby=&quot;prevent-background-page-scroll-with-overscroll-behavior&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Have you ever been annoyed at a page of documentation beginning to scroll after you reached the end of scrolling the sidebar navigation? Controlling this &amp;quot;scroll chain&amp;quot; is the purpose of the &lt;code&gt;overscroll-behavior&lt;/code&gt; property which became cross-browser with Safari 16 in September. The property accepts three values, where &lt;code&gt;contain&lt;/code&gt; is what you&amp;#39;ll want to use to prevent the scroll-chaining effect when the scroll boundary within a subpage element (like the sidebar nav example) is reached.&lt;/p&gt;&lt;p&gt;In the CodePen demo, the &amp;quot;Table of Contents&amp;quot; list area is scrollable and &lt;code&gt;overscroll-behavior: contain&lt;/code&gt; will prevent scrolling of the background article until your mouse leaves the list container.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;abjzWwy&quot; data-user=&quot;5t3ph&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/5t3ph/pen/abjzWwy&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;almost-stable-subgrid-for-grid-layout-inheritance-and-reusability&quot;&gt;Almost stable: `subgrid` for grid layout inheritance and reusability&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#almost-stable-subgrid-for-grid-layout-inheritance-and-reusability&quot; aria-labelledby=&quot;almost-stable-subgrid-for-grid-layout-inheritance-and-reusability&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Subgrid is nearly cross-browser, with &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=618969&quot; rel=&quot;noopener noreferrer&quot;&gt;Chromium lagging just a tiny bit&lt;/a&gt;, but with a prototype in progress which shows their intent to stabilize the feature. Definitely, one to start becoming familiar with for use later in 2023!&lt;/p&gt;&lt;p&gt;Learn &lt;a href=&quot;https://12daysofweb.dev/2022/css-subgrid/&quot;&gt;10 ways subgrid makes grid layout even more powerful&lt;/a&gt; on day 12 from Rachel Andrew. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;whats-next-for-css-in-2023&quot;&gt;What&#39;s next for CSS in 2023?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/2022-css-updates/#whats-next-for-css-in-2023&quot; aria-labelledby=&quot;whats-next-for-css-in-2023&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;I&amp;#39;ll leave you with two places to bookmark to keep on top of changes in CSS:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Interop 2023 will be collective browser benchmarks with areas including CSS where they plan to improve implementations and support. Review &lt;a href=&quot;https://wpt.fyi/interop-2022&quot; rel=&quot;noopener noreferrer&quot;&gt;Interop 2022&lt;/a&gt;, and look out for the release of the 2023 dashboard.&lt;/li&gt;&lt;li&gt;The &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues&quot; rel=&quot;noopener noreferrer&quot;&gt;CSSWG works in public on GitHub&lt;/a&gt; and you can look up issues and discussions and even provide feedback&lt;/li&gt;&lt;/ul&gt;



</content>
  </entry>
  <entry>
    <title>CSS Color Spaces and Relative Color Syntax</title>
    <link href="https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/"/>
    <updated>2022-12-21T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/</id>
    <content type="html">



&lt;p&gt;There are two new specs in the works for CSS that will change how we work with color on the web: &lt;a href=&quot;https://www.w3.org/TR/css-color-4/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Color Module Level 4&lt;/a&gt; (candidate recommendation) and &lt;a href=&quot;https://www.w3.org/TR/css-color-5/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Color Module Level 5&lt;/a&gt; (working draft). Both are still experimental and, as of December 2022, only Safari has an implementation.&lt;/p&gt;&lt;p&gt;We’re going to focus on three things found in these specs: the new syntax for color functions, one of the (many) new color spaces introduced by level 4, and the new relative color syntax from level 5. Combined, these three things are powerful tools for building accessible color palettes with CSS.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;new-color-function-syntax&quot;&gt;New Color Function Syntax&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#new-color-function-syntax&quot; aria-labelledby=&quot;new-color-function-syntax&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;CSS Color Module Level 4 introduces a new syntax for color functions like &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hsl()&lt;/code&gt;. The new syntax omits commas, relying on spaces to separate each of the channels for the color space. It also supports an optional alpha parameter, eliminating the need for additional color functions like &lt;code&gt;rgba()&lt;/code&gt; and &lt;code&gt;hsla()&lt;/code&gt;. The comma-separated forms are now referred to as “legacy syntax” by the spec.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Legacy syntax */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;270&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 40%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* CSS Color Module Level 4 equivalent */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;270 50% 40%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 100% / 50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;True to the web, existing functions like &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hsl()&lt;/code&gt; will continue to support both the new syntax and the legacy, comma-separated syntax. Newer color functions — some of which we’ll look at below — only support the new, space-separated syntax.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;new-color-spaces&quot;&gt;New Color Spaces&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#new-color-spaces&quot; aria-labelledby=&quot;new-color-spaces&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The new color spec adds a whole host of new color spaces to the web: Hue, Whiteness, Blackness (HWB); CIE L*a*b*; Lightness, Chroma, Hue (LCH); Oklab; Oklch; and Display P3, just to name a few. Some of these color spaces — like Display P3 — offer a wider color gamut than the sRGB space we’ve been restricted to on the web since… well, forever. This means that we’ll have access to more colors and that those colors will be more vibrant than the colors we’ve been using, colors that have been available to native app developers for a while.&lt;/p&gt;&lt;p&gt;We’re not going to focus on the wider gamut spaces, though. If you’re interested in learning more about these wide gamut color spaces (or simply what even is a color gamut), I suggest watching Chris Lilley’s CSS Day 2022 talk, &lt;a href=&quot;https://www.youtube.com/watch?v=zkun6wAPc1s&quot; rel=&quot;noopener noreferrer&quot;&gt;Escaping the sRGB Prison (YouTube)&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;We’re going to focus on Oklch. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;oklch&quot;&gt;Oklch&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#oklch&quot; aria-labelledby=&quot;oklch&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Oklch is a polar color space, similar to HSL. It has three channels: lightness (l), chroma (c), and hue (h). Lightness can be either a number between 0 and 1, or a percentage. Hue can be either a number (without units, this corresponds to degrees) or an angle (using units &lt;code&gt;deg&lt;/code&gt;, &lt;code&gt;grad&lt;/code&gt;, &lt;code&gt;rad&lt;/code&gt;, or &lt;code&gt;turn&lt;/code&gt;). Chroma takes either a number (unbounded, but in practice doesn’t exceed 0.5) or a percentage (100% is equivalent to 0.4). Chroma is similar to saturation, but it is independent of the perceived lightness for a given hue.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;perceptual-uniformity&quot;&gt;Perceptual Uniformity&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#perceptual-uniformity&quot; aria-labelledby=&quot;perceptual-uniformity&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We’re focusing on Oklch because, unlike sRGB, Oklch is &lt;code&gt;perceptually uniform&lt;/code&gt;. This means that uniform changes to the lightness channel of a color are evenly spaced visually and that two colors with the same lightness value will have the same perceived lightness — which is not true in a color space like HSL.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/ea01218f-c9da-4901-9fe9-03d856aba44d_Screen+Shot+2022-12-15+at+10.34.30+AM.png?auto=compress,format&quot; alt=&quot;Two color swatches with the same HSL lightness, have very different perceived lightness, as evident when converted to Oklch.&quot; /&gt;&lt;figcaption&gt;Two color swatches with the same HSL lightness, have very different perceived lightness, as evident when converted to Oklch.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;The above example — from the level 4 spec — shows a blue and yellow swatch in sRGB color space, specified by &lt;code&gt;#00F&lt;/code&gt; and &lt;code&gt;#FF0&lt;/code&gt;, respectively. In HSL, both colors have the same lightness value (&lt;code&gt;50%&lt;/code&gt;), but yellow is clearly much lighter than blue. The difference in lightness is reflected in the Oklch color space where the lightness of the blue swatch (&lt;code&gt;0.452&lt;/code&gt;) is much lower than the lightness of the yellow (&lt;code&gt;0.968&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;The above example makes clear that we can’t rely on the lightness channel in HSL to help us create color palettes with enough contrast to be accessible. But by using a perceptually uniform color space like Oklch, we will have a much easier time creating accessible palettes.&lt;/p&gt;&lt;p&gt;If we look at a gradient going from black to white, we can see the difference in lightness between HSL and Oklch. When interpolated through Oklch, each step creates a uniform increase in perceived lightness. When interpolated through HSL, the perceived lightness changes more quickly in darker values than it does in lighter values.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/26d93802-cef7-42f2-bca0-783ae0c9c805_Screen+Shot+2022-12-15+at+10.34.10+AM.png?auto=compress,format&quot; alt=&quot;The same gradient interpolated through two different color spaces — HSL and Oklch — with the mid-gray value marked on each.&quot; /&gt;&lt;figcaption&gt;The same gradient interpolated through two different color spaces — HSL and Oklch — with the mid-gray value marked on each.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;In the above gradients, notice how the darker shades are clustered closer to the left edge of the gradient for HSL than they are for Oklch. The point closest to a mid-gray is marked on each of the gradients. For Oklch, it is approximately in the middle of the gradient, but for HSL, it is slightly to the left of center.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;relative-color-syntax&quot;&gt;Relative Color Syntax&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#relative-color-syntax&quot; aria-labelledby=&quot;relative-color-syntax&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-color-5/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Color Module Level 5&lt;/a&gt; further augments color functions by introducing relative color syntax. This syntax allows you to define a new color based on another color. You use it by first defining an origin color using the &lt;code&gt;from&lt;/code&gt; keyword and then specifying the channels for the new color as usual in the color function.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Relative color syntax only works in the modern, space-separated color formats, not the legacy, comma-separated formats.&lt;/p&gt;&lt;p&gt;When you provide an origin color, you get access to “channel keywords” that allow you to reference each of the channels in the color space. The keywords change depending on the color function you use. For &lt;code&gt;rgb()&lt;/code&gt;, you’d have the &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt;, and &lt;code&gt;b&lt;/code&gt; channel keywords; for &lt;code&gt;oklch()&lt;/code&gt;, you’d have the &lt;code&gt;l&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;h&lt;/code&gt; keywords. For every color function, you also have an &lt;code&gt;alpha&lt;/code&gt; channel keyword, that refers to the origin color’s alpha channel.&lt;/p&gt;&lt;p&gt;You can use these channel keywords in &lt;code&gt;calc()&lt;/code&gt; expressions to modify the original color.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Desaturate the named color tomato in sRGB */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from tomato &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r - 20&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;g - 20&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b - 20&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Create a semi-transparent version of tomato */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from tomato r g b / 50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Darken tomato in oklch */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from tomato &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l - 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; c h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can define relative colors across color spaces as well. When you take a color originally defined in one space and define a new color using a different color space, the browser will first convert the origin color to the new color space.&lt;/p&gt;&lt;p&gt;Here we use Oklch to define a secondary color based on a primary color defined in sRGB by rotating the hue 120° (⅓ of a turn):&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #005f73&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--secondary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; l c &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h + 120&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;relative-colors-for-design-systems&quot;&gt;Relative Colors for Design Systems&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#relative-colors-for-design-systems&quot; aria-labelledby=&quot;relative-colors-for-design-systems&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Sometimes you’ll see people define colors in CSS using one custom property for each color channel — Josh Comeau recently wrote about this in his section on &lt;a href=&quot;https://www.joshwcomeau.com/css/color-formats/#superpowered-design-tokens&quot; rel=&quot;noopener noreferrer&quot;&gt;super-charged design tokens&lt;/a&gt; in his article about color formats. For example, let’s redefine our primary color — &lt;code&gt;#005f73&lt;/code&gt; — in separate &lt;code&gt;l&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;h&lt;/code&gt; channels so we can create shades in Oklch:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Define the channels for primary color in oklch */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary-l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.4485&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary-c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.081&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary-h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 218.73&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Base primary color */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Create a darker shade of the primary color by subtracting 0.1 from the lightness channel */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary-darker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; - 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary-h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can probably see where this is going…&lt;/p&gt;&lt;p&gt;The new relative color syntax removes the need to break each of your colors up into separate channels when you define them. It also allows you to use the most convenient color format for your origin colors regardless of the color space you want to use to modify the origin color.&lt;/p&gt;&lt;p&gt;If you’re working from a design tool that makes it easy to copy sRGB hex values, you can just paste those into your CSS and still use Oklch or Oklab to define perceptually uniform shades.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #005f73&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;--primary-darker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l - 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; c h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;See how much more convenient that is?&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;and-more&quot;&gt;And More…&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#and-more&quot; aria-labelledby=&quot;and-more&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There’s a lot more coming to colors in CSS. The level 5 spec also introduces a &lt;code&gt;color-mix()&lt;/code&gt; function that allows you to &lt;a href=&quot;https://www.w3.org/TR/css-color-5/#color-mix&quot; rel=&quot;noopener noreferrer&quot;&gt;mix colors&lt;/a&gt; in different color spaces — another potentially useful tool in the design system arsenal. And the editor’s draft for the CSS Images Module Level 4 introduces syntax to gradients for defining the &lt;a href=&quot;https://drafts.csswg.org/css-images-4/#funcdef-linear-gradient&quot; rel=&quot;noopener noreferrer&quot;&gt;interpolation space of the gradient&lt;/a&gt;, allowing you to create more vibrant gradients or achieve different artistic effects with your gradients. We glossed over color gamuts, but the new, wider gamut color spaces like Display P3 will give us access to brighter, more vibrant colors than we’ve had access to up until now.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-color-spaces-relative-color-syntax/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-color-4/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Color Module Level 4 &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-color-5/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Color Module Level 5&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-images-4/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Images Module Level 4 Editor’s Draft&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=zkun6wAPc1s&quot; rel=&quot;noopener noreferrer&quot;&gt;Escaping the sRGB Prison (YouTube)&lt;/a&gt; by Chris Lilley, CSS Day 2022&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl&quot; rel=&quot;noopener noreferrer&quot;&gt;OKLCH in CSS: why we moved from RGB and HSL&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/css/color-formats/&quot; rel=&quot;noopener noreferrer&quot;&gt;Color Formats in CSS&lt;/a&gt; by Josh W. Comeau&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://darthmall.net/&quot;&gt;Evan Sheehan&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/d7bf83dd-a782-4771-a77a-3f135a641317_evan.jpeg?auto=compress,format&amp;rect=50,194,567,567&amp;w=150&amp;h=150&quot; alt=&quot;Evan Sheehan&quot; /&gt;
  &lt;p&gt;Evan is a web developer living in Lafayette, CO and working at the &lt;a href=&quot;https://noaa.gov/&quot; rel=&quot;noopener noreferrer&quot;&gt;National Oceanic and Atmospheric Administration&lt;/a&gt;, where he built the website for &lt;a href=&quot;https://sos.noaa.gov/&quot; rel=&quot;noopener noreferrer&quot;&gt;Science On a Sphere&lt;/a&gt; and now builds applications for scientists. You may also sometimes find him playing traditional Irish music on fiddle, playing board games, or out biking.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Evan selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Pointer Events</title>
    <link href="https://12daysofweb.dev/2022/pointer-events/"/>
    <updated>2022-12-20T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/pointer-events/</id>
    <content type="html">



&lt;p&gt;While we&amp;#39;ve long had the ability to detect mouse events with JavaScript, the web was missing a singular interface to detect interaction regardless of input type. &lt;a href=&quot;https://caniuse.com/pointer&quot; rel=&quot;noopener noreferrer&quot;&gt;As of the release of Safari 13&lt;/a&gt; in September 2019, the pointer events API became the cross-browser, unifying solution.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events&quot; rel=&quot;noopener noreferrer&quot;&gt;As MDN docs describe&lt;/a&gt;, a &lt;em&gt;pointer &amp;quot;&lt;/em&gt;is a hardware-agnostic device that can target a specific set of screen coordinates.&amp;quot; Generally, you can consider pointers to include mouse, pen/stylus, or touch interactions.&lt;/p&gt;&lt;p&gt;Pointer events inherit from the mouse events interface, so you receive corresponding events, such as:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;mousedown&lt;/code&gt; / &lt;code&gt;pointerdown&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mouseup&lt;/code&gt; / &lt;code&gt;pointerup&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mousemove&lt;/code&gt; / &lt;code&gt;pointermove&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For backwards compatibility, the browser may opt to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#compatibility_with_mouse_events&quot; rel=&quot;noopener noreferrer&quot;&gt;map these generic events to mouse events&lt;/a&gt;, with some exceptions.&lt;/p&gt;&lt;p&gt;Additional specific pointer event properties include those that tell about the dimensions of the pointer (&lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;), the pressure being applied, the pointer&amp;#39;s tilt, its type, a unique pointer id, and whether it&amp;#39;s the primary pointer of the type.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;The pointer events API is separate from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events&quot; rel=&quot;noopener noreferrer&quot;&gt;`pointer-events` CSS property&lt;/a&gt;, although &lt;code&gt;pointer-events: none&lt;/code&gt; will prevent any attached pointer events.&lt;/p&gt;&lt;/aside&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-pointer-events-to-resize-ui&quot;&gt;Using pointer events to resize UI&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/#using-pointer-events-to-resize-ui&quot; aria-labelledby=&quot;using-pointer-events-to-resize-ui&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To explore how these properties work together and learn two additional pointer methods, we&amp;#39;ll be building &amp;quot;Santa&amp;#39;s Workshop Handbook&amp;quot;  - an online reference for elves and other workshop workers! &lt;/p&gt;&lt;p&gt;The handbook shares a need found in many documentation sites or multi-column application windows: the ability to resize one or more panels to reveal the content or hide it away for more reading or work space.&lt;/p&gt;&lt;p&gt;Fundamentally, the expected interaction is &amp;quot;click and drag,&amp;quot; but pointer events will let us write this to be touch-friendly, too! We&amp;#39;ll also ensure the feature is accessible for keyboard users.&lt;/p&gt;&lt;p&gt;First, we&amp;#39;ll add the basic HTML and CSS for the handbook.&lt;/p&gt;
    

    
    &lt;style&gt;
    .demo {
  padding: 0 !important;
}

.workshop-handbook {
  --panel-width: 200px;

  font-family: system-ui;
  font-size: 1.25rem;
  display: grid;
  align-content: start;
  grid-template-columns: var(--panel-width) 1fr;
  position: relative;
  background-color: firebrick;
  background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39;%3E%3Cdefs%3E%3Cfilter id=&#39;paper&#39; x=&#39;0%25&#39; y=&#39;0%25&#39; width=&#39;100%25&#39; height=&#39;100%25&#39;%3E%3CfeTurbulence type=&#39;fractalNoise&#39; baseFrequency=&#39;0.11&#39; result=&#39;noise&#39; numOctaves=&#39;5&#39; /%3E%3CfeDiffuseLighting in=&#39;noise&#39; lighting-color=&#39;firebrick&#39; surfaceScale=&#39;1.5&#39;%3E%3CfeDistantLight azimuth=&#39;85&#39; elevation=&#39;70&#39; /%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3C/defs%3E%3Crect x=&#39;0&#39; y=&#39;0&#39; width=&#39;100%25&#39; height=&#39;100%25&#39; filter=&#39;url(%23paper)&#39;/%3E%3C/svg%3E&quot;);
  overflow: hidden;
}

.workshop-handbook * {
  margin: 0;
}

.workshop-handbook :is(nav, article) {
  all: unset;
  max-height: 60vh;
  max-height: 60dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.workshop-handbook nav {
  padding: 1rem;
}

.workshop-handbook nav ol {
  padding-left: 0;
  display: grid;
  gap: 1em;
}

.workshop-handbook nav li {
  color: white;
  /* force the overflow and add ellipsis */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.workshop-handbook nav a {
  font-family: Papyrus;
  text-decoration: none;
  color: white;
  position: relative;
  padding-left: 1em;
}

.workshop-handbook nav a:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.workshop-handbook nav a:focus-visible {
  outline: none;
}

.workshop-handbook nav a:focus-visible::before {
  content: &quot;&quot;;
  position: absolute;
  top: calc(50% - 0.5em);
  left: 0;
  border: 0.5em solid transparent;
  border-left-color: currentColor;
}

.workshop-handbook article {
  padding: clamp(1.25rem, 5%, 3rem);
  background-color: #edf9f6;
  background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39;%3E%3Cdefs%3E%3Cfilter id=&#39;paper&#39; x=&#39;0%25&#39; y=&#39;0%25&#39; width=&#39;100%25&#39; height=&#39;100%25&#39;%3E%3CfeTurbulence type=&#39;fractalNoise&#39; baseFrequency=&#39;0.11&#39; result=&#39;noise&#39; numOctaves=&#39;5&#39; /%3E%3CfeDiffuseLighting in=&#39;noise&#39; lighting-color=&#39;%23edf9f6&#39; surfaceScale=&#39;1.5&#39;%3E%3CfeDistantLight azimuth=&#39;85&#39; elevation=&#39;70&#39; /%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3C/defs%3E%3Crect x=&#39;0&#39; y=&#39;0&#39; width=&#39;100%25&#39; height=&#39;100%25&#39; filter=&#39;url(%23paper)&#39;/%3E%3C/svg%3E&quot;);
  line-height: 1.5;
  font-family: Chalkboard, Comic Sans MS;
}

.workshop-handbook article :not(h2) {
  color: #222;
}

.workshop-handbook article * + * {
  margin-top: 1em;
}

.workshop-handbook article h2 {
  color: firebrick;
  font-family: Papyrus;
  font-weight: normal;
}

.workshop-handbook .visually-hidden {
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
}

@media (forced-colors: active) {
  .workshop-handbook :is(nav, article) {
    background-image: none;
  }
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Handbook HTML and CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.demo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--panel-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--panel-width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 1fr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; firebrick&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39;%3E%3Cdefs%3E%3Cfilter id=&#39;paper&#39; x=&#39;0%25&#39; y=&#39;0%25&#39; width=&#39;100%25&#39; height=&#39;100%25&#39;%3E%3CfeTurbulence type=&#39;fractalNoise&#39; baseFrequency=&#39;0.11&#39; result=&#39;noise&#39; numOctaves=&#39;5&#39; /%3E%3CfeDiffuseLighting in=&#39;noise&#39; lighting-color=&#39;firebrick&#39; surfaceScale=&#39;1.5&#39;%3E%3CfeDistantLight azimuth=&#39;85&#39; elevation=&#39;70&#39; /%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3C/defs%3E%3Crect x=&#39;0&#39; y=&#39;0&#39; width=&#39;100%25&#39; height=&#39;100%25&#39; filter=&#39;url(%23paper)&#39;/%3E%3C/svg%3E&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook :is(nav, article)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60dvh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overscroll-behavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; contain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav ol&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding-left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* force the overflow and add ellipsis */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;white-space&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nowrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ellipsis&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Papyrus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding-left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav a:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; underline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-underline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.15em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav a:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook nav a:focus-visible::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50% - 0.5em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-left-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; currentColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.25rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 3rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #edf9f6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39;%3E%3Cdefs%3E%3Cfilter id=&#39;paper&#39; x=&#39;0%25&#39; y=&#39;0%25&#39; width=&#39;100%25&#39; height=&#39;100%25&#39;%3E%3CfeTurbulence type=&#39;fractalNoise&#39; baseFrequency=&#39;0.11&#39; result=&#39;noise&#39; numOctaves=&#39;5&#39; /%3E%3CfeDiffuseLighting in=&#39;noise&#39; lighting-color=&#39;%23edf9f6&#39; surfaceScale=&#39;1.5&#39;%3E%3CfeDistantLight azimuth=&#39;85&#39; elevation=&#39;70&#39; /%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3C/defs%3E%3Crect x=&#39;0&#39; y=&#39;0&#39; width=&#39;100%25&#39; height=&#39;100%25&#39; filter=&#39;url(%23paper)&#39;/%3E%3C/svg%3E&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Chalkboard&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Comic Sans MS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook article :not(h2)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook article * + *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook article h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; firebrick&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Papyrus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook .visually-hidden&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;white-space&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nowrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;forced-colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; active&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.workshop-handbook :is(nav, article)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;workshop-handbook&quot;&gt;
  &lt;nav&gt;
    &lt;ol&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Welcome to the Workshop!&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;A Message From Santa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Hours of Operation&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;North Pole Amenities&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Workshop Etiquette&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Naughty or Nice Management&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Toy-Making Standards&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Misfit Toy Handling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Elf Dress Code&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Meals, Candy and Cocoa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Reindeer Care Guide&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Yeti Prevention&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Snowball Policy&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Ice Removal and Trash Schedule&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Coal Deposit Guidelines&lt;/a&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/nav&gt;
  &lt;article&gt;
    &lt;h2&gt;🎅 Welcome to the Workshop! 🛠&lt;/h2&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod fugiat autem ab? Veritatis?&lt;/p&gt;
    &lt;p&gt;Quisquam omnis mollitia assumenda enim? Eum dolorum unde quasi doloremque perferendis velit in.&lt;/p&gt;
    &lt;p&gt;Cumque qui dolore voluptatibus, reiciendis ipsam optio. Ad nihil repudiandae sunt ratione officiis.&lt;/p&gt;
    &lt;p&gt;Necessitatibus modi blanditiis earum suscipit reiciendis deserunt, placeat, quis perspiciatis, ullam natus magnam?&lt;/p&gt;
    &lt;p&gt;Soluta aspernatur exercitationem iste deserunt? Exercitationem debitis modi maxime nulla officiis facilis eius.&lt;/p&gt;
  &lt;/article&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;We&amp;#39;ve included the &lt;code&gt;--panel-width&lt;/code&gt; custom property for the handbook, which we&amp;#39;ll be manipulating based on the pointer&amp;#39;s position relative to the amount the panel has been moved.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;pointer-target-element&quot;&gt;Pointer target element&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/#pointer-target-element&quot; aria-labelledby=&quot;pointer-target-element&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;What&amp;#39;s missing in the markup so far is a target element to attach pointer events. In this case, a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; is appropriate since it can receive focus and is expected to handle custom events.&lt;/p&gt;&lt;p&gt;Receiving focus is an important aspect since we want our resize trigger to be keyboard accessible, and that&amp;#39;s the first step. That also means we need to consider where it makes sense in the focus order. I&amp;#39;ve decided to place it as the first focus target in the nav so that it&amp;#39;s immediately discoverable for keyboard users.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;resize-trigger&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-describedby&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;resize-description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Resize table of contents&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hidden&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;resize-description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Drag or use left and right arrow keys.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Additionally, this is a custom control, and it doesn&amp;#39;t quite map to any ARIA attributes. It&amp;#39;s not a &amp;quot;drag and drop&amp;quot; since there is no drop target, so we&amp;#39;ve added two important features to clarify the function. &lt;/p&gt;&lt;p&gt;The first is the button label itself which we&amp;#39;ve made &amp;quot;visually hidden&amp;quot; meaning users of assistive technology like screen readers will have the label announced even though it&amp;#39;s not visible. Second, we&amp;#39;ve included a bit more instructions in the &lt;code&gt;[hidden]&lt;/code&gt; paragraph which has a unique &lt;code&gt;id&lt;/code&gt; that&amp;#39;s been referenced within the button&amp;#39;s &lt;code&gt;aria-describedby&lt;/code&gt; attribute. Assistive tech will announce something like &amp;quot;Resize table of contents, button, navigation (short pause) Drag or use left and right arrow keys.&amp;quot; The &amp;quot;navigation&amp;quot; noted in the announcement is due to being the first focus target in the landmark &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; element.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Do you have accessibility improvements to share? I&amp;#39;m always learning, and open to adjusting this article, so &lt;a href=&quot;https://thinkdobecreate.com/contact/&quot; rel=&quot;noopener noreferrer&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;The following demo has been updated to include the &lt;code&gt;.resize-trigger&lt;/code&gt; elements and styles and is visible on &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt;. We&amp;#39;ve also included the related CSS media query to detect a &lt;code&gt;coarse&lt;/code&gt; pointer. This will be often (but not always) be true for touch devices, or when a mouse is not present or not the primary pointing device. This style makes it always visible so it is easier to find and manipulate without a mouse.&lt;/p&gt;
    

    
    &lt;style&gt;
    .workshop-handbook {
  --resize-width: 0.75rem;
}

.workshop-handbook .resize-trigger {
  --resize-bg: linear-gradient(to right, #e4b81e, #9f8837);

  all: unset;
  outline: none;
  position: absolute;
  top: 0;
  left: var(--panel-width);
  width: var(--resize-width);
  height: 100%;
  cursor: ew-resize;
  z-index: 1;
}

.workshop-handbook .resize-trigger:is(:hover, :focus) {
  /* Ensure visibility in forced-colors mode which removes the gradient */
  background-color: Highlight;
  background-image: var(--resize-bg);
  box-shadow: 0 0 5px 1px #f5e096;
  outline: 1px solid transparent;
}

@media (pointer: coarse) {
  .workshop-handbook .resize-trigger {
    background-image: var(--resize-bg);
  }
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Resize trigger element and CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--resize-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook .resize-trigger&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--resize-bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;to right&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #e4b81e&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #9f8837&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--panel-width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--resize-width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ew-resize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.workshop-handbook .resize-trigger:is(:hover, :focus)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Ensure visibility in forced-colors mode which removes the gradient */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Highlight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--resize-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 5px 1px #f5e096&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; coarse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.workshop-handbook .resize-trigger&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--resize-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;workshop-handbook&quot;&gt;
  &lt;nav&gt;
    &lt;button type=&quot;button&quot; class=&quot;resize-trigger&quot; aria-describedby=&quot;resize-description&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Resize navigation&lt;/span&gt;&lt;/button&gt;
    &lt;p hidden=&quot;&quot; id=&quot;resize-description&quot;&gt;Drag or use left and right arrow keys.&lt;/p&gt;
    &lt;ol&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Welcome to the Workshop!&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;A Message From Santa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Hours of Operation&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;North Pole Amenities&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Workshop Etiquette&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Naughty or Nice Management&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Toy-Making Standards&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Misfit Toy Handling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Elf Dress Code&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Meals, Candy and Cocoa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Reindeer Care Guide&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Yeti Prevention&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Snowball Policy&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Ice Removal and Trash Schedule&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Coal Deposit Guidelines&lt;/a&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/nav&gt;
  &lt;article&gt;
    &lt;h2&gt;🎅 Welcome to the Workshop! 🛠&lt;/h2&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod fugiat autem ab? Veritatis?&lt;/p&gt;
    &lt;p&gt;Quisquam omnis mollitia assumenda enim? Eum dolorum unde quasi doloremque perferendis velit in.&lt;/p&gt;
    &lt;p&gt;Cumque qui dolore voluptatibus, reiciendis ipsam optio. Ad nihil repudiandae sunt ratione officiis.&lt;/p&gt;
    &lt;p&gt;Necessitatibus modi blanditiis earum suscipit reiciendis deserunt, placeat, quis perspiciatis, ullam natus magnam?&lt;/p&gt;
    &lt;p&gt;Soluta aspernatur exercitationem iste deserunt? Exercitationem debitis modi maxime nulla officiis facilis eius.&lt;/p&gt;
  &lt;/article&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-the-pointer-events-api&quot;&gt;Using the pointer events API&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/#using-the-pointer-events-api&quot; aria-labelledby=&quot;using-the-pointer-events-api&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now that the HTML is in place, it&amp;#39;s time to make the resize trigger work with pointer events!&lt;/p&gt;&lt;p&gt;The basic flow is as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;On &lt;code&gt;pointerdown&lt;/code&gt;, start tracking the &lt;code&gt;clientX&lt;/code&gt; position during &lt;code&gt;onpointermove&lt;/code&gt;. Additionally, use &lt;code&gt;setPointerCapture()&lt;/code&gt; to continue tracking only this pointer while &lt;code&gt;pointerdown&lt;/code&gt; is active.&lt;/li&gt;&lt;li&gt;On &lt;code&gt;pointerup&lt;/code&gt;, remove the &lt;code&gt;onpointermove&lt;/code&gt; event to end the drag functionality and stop tracking the pointer with &lt;code&gt;releasePointerCapture()&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The &lt;code&gt;resizePanel()&lt;/code&gt; script receives the &lt;code&gt;clientX&lt;/code&gt; position or other provided integer and compares it to the boundary of the handbook and a minimum and maximum size we&amp;#39;ll allow for the panel. If the number is an allowed size, it updates the &lt;code&gt;--panel-width&lt;/code&gt; CSS custom property which ultimately is responsible for the resizing since it sets the grid column width for the navigation.&lt;/p&gt;&lt;p&gt;Finally, for purposes of our application, we listen for &lt;code&gt;keydown&lt;/code&gt; so that we can detect the &lt;code&gt;ArrowLeft&lt;/code&gt; and &lt;code&gt;ArrowRight&lt;/code&gt; keys to allow keyboard users to resize the panel, too.&lt;/p&gt;
    

    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Resizing pointer events&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; handbook &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;handbook&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; panelResize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handbook&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.resize-trigger&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; handbookBoundaries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handbook&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rightBoundary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handbookBoundaries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; leftBoundary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handbookBoundaries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentMin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;resizePanel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; contentMin &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; rightBoundary &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; leftBoundary &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; contentMin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    handbook&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--panel-width&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;size&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create drag and move interaction&lt;/span&gt;&lt;br /&gt;panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pointerdown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pointerId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onpointermove&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; clientX &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Adjust position since demo is not a fullwidth window application&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; panelPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clientX &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; leftBoundary&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;resizePanel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;panelPos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setPointerCapture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pointerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Release resizer when drag ends / mouse is disengaged&lt;/span&gt;&lt;br /&gt;panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pointerup&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pointerId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onpointermove &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;releasePointerCapture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pointerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Allow keyboard resizing&lt;/span&gt;&lt;br /&gt;panelResize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;keydown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; key &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ArrowLeft&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ArrowRight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// get current value and add or remove 10px&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; posX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handbook&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--panel-width&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ArrowLeft&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      posX &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      posX &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;resizePanel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;posX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;handbook&quot; class=&quot;workshop-handbook&quot;&gt;
  &lt;nav&gt;
    &lt;button type=&quot;button&quot; class=&quot;resize-trigger&quot; aria-describedby=&quot;resize-description-2&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Resize navigation&lt;/span&gt;&lt;/button&gt;
    &lt;p hidden=&quot;&quot; id=&quot;resize-description-2&quot;&gt;Drag or use left and right arrow keys.&lt;/p&gt;
    &lt;ol&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Welcome to the Workshop!&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;A Message From Santa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Hours of Operation&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;North Pole Amenities&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Workshop Etiquette&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Naughty or Nice Management&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Toy-Making Standards&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Misfit Toy Handling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Elf Dress Code&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Meals, Candy and Cocoa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Reindeer Care Guide&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Yeti Prevention&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Snowball Policy&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Ice Removal and Trash Schedule&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/&quot;&gt;Coal Deposit Guidelines&lt;/a&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/nav&gt;
  &lt;article&gt;
    &lt;h2&gt;🎅 Welcome to the Workshop! 🛠&lt;/h2&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod fugiat autem ab? Veritatis?&lt;/p&gt;
    &lt;p&gt;Quisquam omnis mollitia assumenda enim? Eum dolorum unde quasi doloremque perferendis velit in.&lt;/p&gt;
    &lt;p&gt;Cumque qui dolore voluptatibus, reiciendis ipsam optio. Ad nihil repudiandae sunt ratione officiis.&lt;/p&gt;
    &lt;p&gt;Necessitatibus modi blanditiis earum suscipit reiciendis deserunt, placeat, quis perspiciatis, ullam natus magnam?&lt;/p&gt;
    &lt;p&gt;Soluta aspernatur exercitationem iste deserunt? Exercitationem debitis modi maxime nulla officiis facilis eius.&lt;/p&gt;
  &lt;/article&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const handbook = document.getElementById(&quot;handbook&quot;);
const panelResize = handbook.querySelector(&quot;.resize-trigger&quot;);
const handbookBoundaries = handbook.getBoundingClientRect();
const rightBoundary = handbookBoundaries.right;
const leftBoundary = handbookBoundaries.left;
const contentMin = 150;

const resizePanel = (size) =&gt; {
  if (size &gt;= contentMin &amp;&amp; size &lt;= rightBoundary - leftBoundary - contentMin) {
    handbook.style.setProperty(&quot;--panel-width&quot;, `${size}px`);
  }
};

// Create drag and move interaction
panelResize.addEventListener(&quot;pointerdown&quot;, ({ pointerId }) =&gt; {
  panelResize.onpointermove = ({ clientX }) =&gt; {
    // Adjust position since demo is not a fullwidth window application
    const panelPos = clientX - leftBoundary;
    resizePanel(panelPos);
  };
  panelResize.setPointerCapture(pointerId);
});

// Release resizer when drag ends / mouse is disengaged
panelResize.addEventListener(&quot;pointerup&quot;, ({ pointerId }) =&gt; {
  panelResize.onpointermove = null;
  panelResize.releasePointerCapture(pointerId);
});

// Allow keyboard resizing
panelResize.addEventListener(&quot;keydown&quot;, ({ key }) =&gt; {
  if ([&quot;ArrowLeft&quot;, &quot;ArrowRight&quot;].includes(key)) {
    // get current value and add or remove 10px
    let posX = parseInt(
      getComputedStyle(handbook).getPropertyValue(&quot;--panel-width&quot;)
    );

    if (key === &quot;ArrowLeft&quot;) {
      posX -= 10;
    } else {
      posX += 10;
    }

    resizePanel(posX);
  }
});
    &lt;/script&gt;
    

    

    
    &lt;aside role=&quot;note&quot;&gt;&lt;p&gt;If you&amp;#39;re viewing in portrait on a mobile device or otherwise have a narrow viewport, you&amp;#39;ll not have too much room to move the panel given the small range once we reserve 100px from the left and right edges. So rotate to landscape &lt;em&gt;and reload&lt;/em&gt; or try again later on a larger viewport if you have one available!&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/pointer-events/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Learn more about pointer events from the following resources:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events&quot; rel=&quot;noopener noreferrer&quot;&gt;Pointer events API docs&lt;/a&gt; on MDN&lt;/li&gt;&lt;li&gt;Also see the pointer events docs as related to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events/Using_Pointer_Events&quot; rel=&quot;noopener noreferrer&quot;&gt;canvas and a drawing app demo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture#examples&quot; rel=&quot;noopener noreferrer&quot;&gt;Docs for `setPointerCapture()`&lt;/a&gt; show an additional example of changing an element&amp;#39;s position&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>CSS Scroll Snap</title>
    <link href="https://12daysofweb.dev/2022/css-scroll-snap/"/>
    <updated>2022-12-19T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/css-scroll-snap/</id>
    <content type="html">



&lt;p&gt;With scrolling on the web, there&amp;#39;s a feature called &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Scroll_Snap&quot; rel=&quot;noopener noreferrer&quot;&gt;Scroll Snap&lt;/a&gt; which allows authors to articulate mandatory or optional resting places for scroll. A common initial use case is for carousel-like scrolling.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;bGvoZpK&quot; data-user=&quot;argyleink&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/bGvoZpK&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;Each of those rows of items uses scroll snapping but tells each row of items to snap to a different spot in the scrollable area. The top one snaps items to the beginning with &lt;code&gt;scroll-snap-align: start&lt;/code&gt;. The middle example snaps items to the center of the scroll area with &lt;code&gt;scroll-snap-align: center&lt;/code&gt;. The last example snaps items to the end of the scroll area with &lt;code&gt;scroll-snap-align: end&lt;/code&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;Several of Adam&amp;#39;s demos are built using cascade layers (reviewed on &lt;a href=&quot;https://12daysofweb.dev/2022/cascade-layers/&quot;&gt;Day 5&lt;/a&gt;!), be sure you&amp;#39;re using a &lt;a href=&quot;https://caniuse.com/css-cascade-layers&quot; rel=&quot;noopener noreferrer&quot;&gt;supporting browser&lt;/a&gt;. The &lt;code&gt;@layer&lt;/code&gt; syntax is a CSS organization choice and not required for scroll-snapping.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-basics&quot;&gt;The basics&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-scroll-snap/#the-basics&quot; aria-labelledby=&quot;the-basics&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The achieve a scroll-snapping scroll experience, there are 2 essential parts to establish:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;A scrollable container with &lt;code&gt;overflow&lt;/code&gt; that adds `&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type&quot; rel=&quot;noopener noreferrer&quot;&gt;scroll-snap-type&lt;/a&gt;` which says the scrollable viewport can be snapped to, which axis to do the snapping, and whether or not it&amp;#39;s a requirement to snap (&lt;code&gt;mandatory&lt;/code&gt;) or optional (&lt;code&gt;proximity&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;One or many children of a scroll-snap container that specifies where to snap with `&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-align&quot; rel=&quot;noopener noreferrer&quot;&gt;scroll-snap-align&lt;/a&gt;` which says, on an item-by-item basis, where it should snap within that container&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;You&amp;#39;re not limited to a single axis either. A horizontal scrolling snap experience may be the first place your design mind goes to with the feature, but consider this example where snapping can occur on both the x and y-axis.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;GRxMPGb&quot; data-user=&quot;argyleink&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/GRxMPGb&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;The scroll container specifies it can be scrolled horizontally and vertically, that it&amp;#39;s a snap area, and each child should snap to the center. &lt;/p&gt;&lt;p&gt;This demo is also a good time to introduce the scroll-snap devtools in Chromium browsers. &lt;a href=&quot;https://cdpn.io/pen/debug/GRxMPGb&quot; rel=&quot;noopener noreferrer&quot;&gt;Open the codepen&lt;/a&gt; in a new tab and inspect the grid. Look for the &lt;code&gt;scroll-snap&lt;/code&gt; badge in the elements panel and click it to enable the debugging overlay:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/4769c38b-f532-4691-b3ae-7d084aed23b9_scrollsnap-devtools.png?auto=compress,format&quot; alt=&quot;Preview of a scroll-snap container selected from the DOM using Chrome devtools showing the &amp;#39;scroll-snap&amp;#39; badge.&quot; /&gt;&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/797a0cd2-a27a-400c-8784-2e6eeca0a13c_scrollsnap-overlay.png?auto=compress,format&quot; alt=&quot;Chrome devtools is opened to the left of the &amp;#39;Snap Matrix&amp;#39; CodePen and the &amp;#39;scroll-snap&amp;#39; badge has been clicked, revealing the overlay described next.&quot; /&gt;&lt;/p&gt;&lt;p&gt;The scroll-snap overlay puts a purple border around the scroll area and a dot on each item that has &lt;code&gt;scroll-snap-align&lt;/code&gt; on it. These items all want to snap to the center, so they all have a dot in the center. It also will show overflowing items which is really handy. Here I&amp;#39;ve constrained the height and width of the scroll area so we can see the overflow and snap alignment.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/7f3082ba-7ea3-4e8a-a2eb-7b608030a237_scrollsnap-expandedoverlay.png?auto=compress,format&quot; alt=&quot;The scroll-snap overlay is visible even outside of the boundaries of the container, revealing the overflowing scroll-snap items.&quot; /&gt;&lt;/p&gt;&lt;p&gt;For a practical application of scroll snapping, I made a media scrolling experience on &lt;a href=&quot;https://web.dev/building-a-media-scroller-component/&quot; rel=&quot;noopener noreferrer&quot;&gt;GUI Challenges&lt;/a&gt; that emulates the browsing experience for many media networks. It also features great keyboard navigation and use of `&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scroll-padding&quot; rel=&quot;noopener noreferrer&quot;&gt;scroll-padding&lt;/a&gt;` to create an edge-to-edge scroll experience that rests in perfect alignment with its section header.&lt;/p&gt;&lt;p&gt;Check out the &lt;a href=&quot;https://gui-challenges.web.app/media-scroller/dist/&quot; rel=&quot;noopener noreferrer&quot;&gt;media scroller demo&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;advanced&quot;&gt;Advanced&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-scroll-snap/#advanced&quot; aria-labelledby=&quot;advanced&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;So far we&amp;#39;ve put snap alignment on every direct child of the scroll container like &lt;code&gt;.scroll-container &amp;gt; *&lt;/code&gt;, but things get interesting when there&amp;#39;s only one or a couple of snap targets.&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;JjLOEVW&quot; data-user=&quot;argyleink&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/JjLOEVW&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;In the above demo, the edge most elements &lt;strong&gt;are not&lt;/strong&gt; snap targets, and when that is combined with &lt;code&gt;mandatory&lt;/code&gt; snapping specified on the scroll container, it gives a nice bouncy effect to the edges of scrolling (often called an overscroll effect). &lt;/p&gt;&lt;p&gt;You can also have scroll areas inside of scroll areas, each with its own snapping:&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;gOzPYOj&quot; data-user=&quot;argyleink&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/gOzPYOj&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;In the following demo, only 1 element is a snap target (the most recent/last message) which keeps the scroll container at the bottom, even as new messages are added:&lt;/p&gt;&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;RwPWqKe&quot; data-user=&quot;argyleink&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/RwPWqKe&quot;&gt;See the CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-scroll-snap/#conclusion&quot; aria-labelledby=&quot;conclusion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There&amp;#39;s a lot more you can do with scroll snap on the web. I&amp;#39;ve created a &lt;a href=&quot;https://codepen.io/collection/KpqBGW&quot; rel=&quot;noopener noreferrer&quot;&gt;collection on Codepen&lt;/a&gt; to make them easy to discover and take code from. That&amp;#39;s the grab-n-go aspect of this article! &lt;/p&gt;&lt;p&gt;Hopefully, this gave you an overview of the design opportunities with scroll snap. There&amp;#39;s a lot of potential to enhance a scroll experience with healthy scrolling resting places.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://12daysofweb.dev/2022/css-scroll-snap/&quot;&gt;Adam Argyle&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/51ca211b-b706-4e1b-91a1-883489a52d37_adam.jpeg?auto=compress,format&amp;rect=372,37,1025,1025&amp;w=150&amp;h=150&quot; alt=&quot;Adam Argyle&quot; /&gt;
  &lt;p&gt;Adam is a bright, passionate, punk engineer with an adoration for the web who prefers using his skills for best in class UI/UX and empowering those around him. He’s worked at small and large companies, and built an app for pretty much every screen (or voice). He is capable of over-engineering, but spends lots of brain power not. Loves CSS, loves JS, loves great UX. He&amp;#39;s also a member of the CSS Working Group, VisBug and Open Props creator, and overall web fan.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Adam selected &lt;strong&gt;&lt;a href=&quot;https://wearebgc.org/&quot;&gt;Black Girls Code&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://wearebgc.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/e2dce7ca-44f9-4eae-9161-b063b66a8957_blackgirlscode.jpeg?auto=compress,format&quot; alt=&quot;Black Girls Code&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;We build pathways for young women of color to embrace the current tech marketplace as builders and creators by introducing them to skills in computer programming and technology.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>HTML Dialog</title>
    <link href="https://12daysofweb.dev/2022/dialog/"/>
    <updated>2022-12-18T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/dialog/</id>
    <content type="html">



&lt;p&gt;The HTML element &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; has had a long history, first landing in Chrome in 2014! While iterations have had issues largely &lt;a href=&quot;https://www.scottohara.me/blog/2019/03/05/open-dialog.html&quot; rel=&quot;noopener noreferrer&quot;&gt;pertaining to accessibility&lt;/a&gt;, it has gained cross-browser stability in 2022.&lt;/p&gt;&lt;p&gt;Before we get into a demo and review implementation features, it&amp;#39;s important to understand the difference between the two types: modal and non-modal.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;modal-dialogs&quot;&gt;Modal dialogs&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#modal-dialogs&quot; aria-labelledby=&quot;modal-dialogs&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Modal dialogs are user interface elements that become the &amp;quot;top layer&amp;quot; above the rest of the DOM and require interaction that interrupts a user&amp;#39;s flow. They have a fixed (non-moveable) position and cover the underlying page with a typically semi-transparent overlay which is the pseudo-element &lt;code&gt;::backdrop&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;When a modal dialog is open, the content behind the page should be rendered &lt;code&gt;inert&lt;/code&gt; - in other words, it should have interactivity removed, appearing static. The inert behavior creates a &amp;quot;focus trap&amp;quot; in the modal, meaning a keyboard user can enter the modal and not be able to have focus exit to the page behind until the modal is closed. While &lt;a href=&quot;https://developer.chrome.com/articles/inert/&quot; rel=&quot;noopener noreferrer&quot;&gt;an attribute for inert&lt;/a&gt; is gaining browser support, a benefit of modal usage of the dialog element is automatic inert behavior. This again is tied to use of the &lt;code&gt;showModal() &lt;/code&gt;method.&lt;/p&gt;&lt;p&gt;Another expectation of modal dialogs by keyboard users is the ability to close them using the &lt;code&gt;Esc&lt;/code&gt; key, which the &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element provides when launched using the &lt;code&gt;showModal()&lt;/code&gt; method.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;non-modal-dialogs&quot;&gt;Non-modal dialogs&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#non-modal-dialogs&quot; aria-labelledby=&quot;non-modal-dialogs&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Non-modal dialogs refer to typically anchored overlays that do not block the page. When open, a user still has access to interact with the page content. They should not be used if the action requires user input or interaction. &lt;/p&gt;&lt;p&gt;Examples include the &amp;quot;Compose&amp;quot; window for an email application, a newsletter sign-up nudge on a blog, a find and replace handler, an onboarding tutorial pointer, or any other sort of sub-window interface. You may choose to enable the non-modal dialog to be repositioned by the user. &lt;/p&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element can be used as a non-modal dialog when launched with the &lt;code&gt;show()&lt;/code&gt; method. A close action must be provided and non-modal dialogs require user interaction to close them.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;dialog-demo&quot;&gt;Dialog demo&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#dialog-demo&quot; aria-labelledby=&quot;dialog-demo&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s create a modal dialog for confirming whether a user would like to eat a penguin cookie off of a virtual cookie tray!&lt;/p&gt;&lt;p&gt;First, let&amp;#39;s start off by designing the markup and styles for our tray of penguin cookies.&lt;/p&gt;&lt;p&gt;We&amp;#39;ll use a list that contains our cookie image within buttons. The list semantics will help indicate to users of assistive technology like screen readers how many cookies are left on the tray. And &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; is the appropriate interactive element to trigger the dialog.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select a cookie to eat!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-tray&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;penguin cookie #1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;penguin cookie #2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ...additional cookie list items --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;style&gt;
    .dialog-demo {
  padding: 5vmin;
  background-color: #ec4913;
  color: #444;
}

.dialog-demo h2 {
  text-align: center;
  margin-bottom: 3vh;
  color: white;
  font-size: clamp(2rem, 5vw + 1rem, 3.5rem);
}

.dialog-demo h3 {
  margin-bottom: 1rem;
}

.dialog-demo button {
  all: unset;
}

.dialog-demo button * {
  pointer-events: none;
}

.dialog-demo button:focus-visible {
  outline: 2px solid var(--button-focus, red);
}

.cookie-tray {
  --cookie-size: max(12vh, 80px);

  list-style: none;
  padding: 5vmin;
  margin: 0 auto;
  position: relative;
  max-width: 80ch;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--cookie-size)), 1fr));
  gap: 1vmax;
  background-color: silver;
  box-shadow: inset 0 0 6vmin 1vmin rgba(0, 0, 0, 0.65);
  border-radius: 3vmin;
}

.cookie-tray:focus-visible {
  outline: 2px solid black;
  outline-offset: -4px;
}

.cookie-tray li {
  display: grid;
  place-content: center;
  height: var(--cookie-size);
  margin: 0;
}

.cookie-tray .cookie {
  border-radius: 2rem;
  padding: 3%;
  cursor: grab;
}

.cookie-tray .cookie img {
  max-width: 100%;
  height: var(--cookie-size);
  display: block;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Cookie tray HTML and CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5vmin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ec4913&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #444&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5vw + 1rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 3.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo button *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;pointer-events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.dialog-demo button:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-focus&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.cookie-tray&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--cookie-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;12vh&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 80px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5vmin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 80ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auto-fit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;minmax&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--cookie-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1fr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1vmax&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; silver&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inset 0 0 6vmin 1vmin &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.65&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3vmin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.cookie-tray:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.cookie-tray li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--cookie-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.cookie-tray .cookie&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grab&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.cookie-tray .cookie img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--cookie-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;dialog-demo&quot;&gt;

  &lt;h2&gt;Select a cookie to eat!&lt;/h2&gt;

  &lt;ul role=&quot;list&quot; class=&quot;cookie-tray&quot;&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #1&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #2&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #3&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #4&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #5&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #6&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;dialog-html-and-content&quot;&gt;Dialog HTML and content&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#dialog-html-and-content&quot; aria-labelledby=&quot;dialog-html-and-content&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Our &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; aims to confirm whether a user intended to &amp;quot;eat&amp;quot; the penguin cookie. We will include two buttons to select either &amp;quot;Eat Cookie&amp;quot; or &amp;quot;Cancel&amp;quot;. I&amp;#39;ve opted for custom data attributes to distinguish the button actions from one another.&lt;/p&gt;&lt;p&gt;Also, note the &lt;code&gt;.cookie-name&lt;/code&gt; element, which we&amp;#39;ll populate via JavaScript shortly.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;dialog&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-confirmation&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dialog-content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Cookie Selection Confirmation&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Are you sure you want to eat &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;strong&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;?&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dialog-actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;confirm&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Eat Cookie&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cancel&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Cancel&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;dialog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Additionally, we&amp;#39;ve added a presentational &lt;code&gt;div.dialog-content&lt;/code&gt; which will soon enable us to include the ability to dismiss the modal from a click on the backdrop.&lt;/p&gt;&lt;p&gt;At this point, the dialog is not visible unless we add the &lt;code&gt;open&lt;/code&gt; attribute (leading the browser to treat it as non-modal) or add a small bit of script to launch it. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt; The use of the &lt;code&gt;open&lt;/code&gt; attribute is not recommended because it is possible to have state conflicts between the attribute and the dialog JS methods.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;opening-the-dialog&quot;&gt;Opening the dialog&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#opening-the-dialog&quot; aria-labelledby=&quot;opening-the-dialog&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Since we want the modal behavior of the dialog, our script essentially involves detecting a click on a &lt;code&gt;.cookie&lt;/code&gt; button and attaching the &lt;code&gt;showModal()&lt;/code&gt; method to the dialog. We&amp;#39;re also taking advantage of image semantics to grab the &lt;code&gt;alt&lt;/code&gt; value and populate the &lt;code&gt;.cookie-name&lt;/code&gt;.&lt;/p&gt;
    

    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Dialog open script&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dialog1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cookie-confirmation-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dialog-demo-1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Populate the .cookie-name with the img `alt` value&lt;/span&gt;&lt;br /&gt;    dialog1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Open the dialog as a modal&lt;/span&gt;&lt;br /&gt;    dialog1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showModal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;dialog-demo-1&quot; class=&quot;dialog-demo&quot;&gt;

  &lt;h2&gt;Select a cookie to eat!&lt;/h2&gt;

  &lt;ul role=&quot;list&quot; class=&quot;cookie-tray&quot;&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #1&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #2&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #3&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #4&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #5&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #6&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
  &lt;/ul&gt;

  &lt;dialog id=&quot;cookie-confirmation-1&quot;&gt;
    &lt;div class=&quot;dialog-content&quot;&gt;
      &lt;h3&gt;Cookie Selection Confirmation&lt;/h3&gt;
      &lt;p&gt;Are you sure you want to eat &lt;strong class=&quot;cookie-name&quot;&gt;&lt;/strong&gt;?&lt;/p&gt;
      &lt;ul class=&quot;dialog-actions&quot;&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;confirm&quot;&gt;Eat Cookie&lt;/button&gt;&lt;/li&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;cancel&quot;&gt;Cancel&lt;/button&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  &lt;/dialog&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const dialog1 = document.getElementById(&quot;cookie-confirmation-1&quot;);

document.getElementById(&#39;dialog-demo-1&#39;).addEventListener(&quot;click&quot;, ({ target }) =&gt; {
  if (target.matches(&quot;.cookie&quot;)) {
    // Populate the .cookie-name with the img `alt` value
    dialog1.querySelector(&quot;.cookie-name&quot;).textContent = target.querySelector(
      &quot;img&quot;
    ).alt;

    // Open the dialog as a modal
    dialog1.showModal();
  }
});
    &lt;/script&gt;
    

    

    
    &lt;p&gt;If you&amp;#39;re following along at home, since we haven&amp;#39;t styled the dialog, here&amp;#39;s the default &lt;code&gt;dialog&lt;/code&gt; appearance in Chromium, including the positioning, which is not currently relative to our cookie tray but to the viewport (some content styles have been established).&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/b2cc9010-0902-4fd6-805e-60ccdc6f3364_Screen+Shot+2022-12-13+at+10.39.16+AM.png?auto=compress,format&quot; alt=&quot;The default dialog is white with a black border and has a fixed position to the top and center of the viewport, so is shown overlapping the demo and the prior content.&quot; /&gt;&lt;/p&gt;&lt;p&gt;Because &amp;quot;Eat Cookie&amp;quot; is the first focusable element, by default, the browser will focus it when the dialog is opened. If you need to change the first-focused element, you can add the &lt;code&gt;autofocus&lt;/code&gt; attribute. &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Note that if you determine that the dialog itself or something like a headline or other non-interactive element should be focused, you&amp;#39;ll need to add &lt;code&gt;tabindex=&amp;quot;0&amp;quot;&lt;/code&gt; to enable it as focusable. I recommend Adrian Roselli&amp;#39;s article to &lt;a href=&quot;https://adrianroselli.com/2020/10/dialog-focus-in-screen-readers.html&quot; rel=&quot;noopener noreferrer&quot;&gt;learn more about dialog focus management&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Through testing with VoiceOver on Mac, the &lt;code&gt;h3&lt;/code&gt; title is also read out before announcing the focused button, which helps lend context to the action.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;closing-the-dialog&quot;&gt;Closing the dialog&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#closing-the-dialog&quot; aria-labelledby=&quot;closing-the-dialog&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We haven&amp;#39;t yet added a script to indicate an element to close the button, but the &lt;code&gt;Esc&lt;/code&gt; key is enabled for closing due to using the &lt;code&gt;showModal()&lt;/code&gt; method (refer back to the &amp;quot;&lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#modal-vs-non-modal-dialogs&quot;&gt;Modal vs. non-modal dialogs&lt;/a&gt;&amp;quot; section). This behavior is not available when using the &lt;code&gt;show()&lt;/code&gt; method for non-modal dialogs.&lt;/p&gt;&lt;p&gt;Due to how we want our modal to work, we will enable closing of the dialog for both buttons as a starting point. The following enhances our previous dialog script.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ... show logic&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Close the dialog when either action button is clicked&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[data-action]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;removing-cookies&quot;&gt;Removing cookies&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#removing-cookies&quot; aria-labelledby=&quot;removing-cookies&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There&amp;#39;s one more behavior we want for our modal which is when the confirm button for &amp;quot;Eat cookie&amp;quot; is selected then we need to remove the selected cookie.&lt;/p&gt;&lt;p&gt;Upon closing a dialog, the browser will place focus back on the element that launched the dialog. We can take advantage of this behavior to remove that cookie. The browser tracks the currently focused element via &lt;code&gt;document.activeElement&lt;/code&gt;.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Prior to Safari 16.1, the focus may not return to the triggering element. The full demo includes one method of workaround to still find the element that launched the dialog for our use case.&lt;/p&gt;&lt;/aside&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ... show logic&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ... close logic&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;confirm&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// find cookie based on active focus&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookie &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// remove cookie from DOM&lt;/span&gt;&lt;br /&gt;    cookie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, we also need to define a replacement element to give focus to. &lt;/p&gt;&lt;p&gt;In this case, we&amp;#39;ll enable the &lt;code&gt;.cookie-tray&lt;/code&gt; unordered list as a programmatically focusable element by adding &lt;code&gt;tabindex=&amp;quot;-1&amp;quot;&lt;/code&gt;. We&amp;#39;ll also update the headline to add an &lt;code&gt;id&lt;/code&gt; attribute which we&amp;#39;ll reference from the &lt;code&gt;aria-labelledby&lt;/code&gt; attribute on the list. This will help re-orient screen reader users after the cookie disappears and the focus is moved.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Updates to the headline and `ul` --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-tray-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select a cookie to eat!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-tray&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tabindex&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;-1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-labelledby&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cookie-tray-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, update the script to add the focus to &lt;code&gt;.cookie-tray&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieTray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-tray&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;confirm&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Set focus to ul.cookie-tray&lt;/span&gt;&lt;br /&gt;    cookieTray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As a bonus of &lt;code&gt;.cookie-tray&lt;/code&gt; being a list element, the announced number of list items will update to only include non-empty list items, therefore accurately reflecting the number of cookies visible on the tray!&lt;/p&gt;&lt;p&gt;Depending on your reason for removing DOM elements, you may need to alter this logic to instead move focus to the next, first, or last item in the list depending on the position of the removed element.&lt;/p&gt;
    

    

    
    &lt;details&gt;
    &lt;summary&gt;Fully working dialog&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dialog2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cookie-confirmation-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieTray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#dialog-demo-2 .cookie-tray&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dialog-demo-2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    dialog2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showModal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[data-action]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;confirm&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookie &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      cookie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Safari prior to 16.1 does not re-focus dialog triggering element&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dialog2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      cookieTray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookieName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    cookieTray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;dialog-demo-2&quot; class=&quot;dialog-demo&quot;&gt;

  &lt;h2 id=&quot;cookie-tray-title&quot;&gt;Select a cookie to eat!&lt;/h2&gt;

  &lt;ul role=&quot;list&quot; class=&quot;cookie-tray&quot; tabindex=&quot;-1&quot; aria-labelledby=&quot;cookie-tray-title&quot;&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #1&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #2&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #3&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #4&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #5&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #6&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
  &lt;/ul&gt;

  &lt;dialog id=&quot;cookie-confirmation-2&quot;&gt;
    &lt;div class=&quot;dialog-content&quot;&gt;
      &lt;h3&gt;Cookie Selection Confirmation&lt;/h3&gt;
      &lt;p&gt;Are you sure you want to eat &lt;strong class=&quot;cookie-name&quot;&gt;&lt;/strong&gt;?&lt;/p&gt;
      &lt;ul class=&quot;dialog-actions&quot;&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;confirm&quot;&gt;Eat Cookie&lt;/button&gt;&lt;/li&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;cancel&quot;&gt;Cancel&lt;/button&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  &lt;/dialog&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const dialog2 = document.getElementById(&quot;cookie-confirmation-2&quot;);
const cookieTray = document.querySelector(&quot;#dialog-demo-2 .cookie-tray&quot;);

document.getElementById(&#39;dialog-demo-2&#39;).addEventListener(&quot;click&quot;, ({ target }) =&gt; {
  if (target.matches(&quot;.cookie&quot;)) {
    dialog2.querySelector(&quot;.cookie-name&quot;).textContent = target.querySelector(
      &quot;img&quot;
    ).alt;
    dialog2.showModal();
  }

  if (target.matches(&quot;[data-action]&quot;)) {
    dialog2.close();
  }

  if (target.matches(&#39;[data-action=&quot;confirm&quot;]&#39;)) {
    const cookie = document.activeElement;
    if (cookie.matches(&quot;.cookie&quot;)) {
      cookie.remove();
    } else {
      // Safari prior to 16.1 does not re-focus dialog triggering element
      const cookieName = dialog2.querySelector(&quot;.cookie-name&quot;).textContent;
      cookieTray.querySelectorAll(&quot;.cookie img&quot;).forEach((c) =&gt; {
        if (c.alt.includes(cookieName)) {
          c.closest(&quot;.cookie&quot;).remove();
        }
      });
    }
    cookieTray.focus();
  }
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;styling-the-dialog&quot;&gt;Styling the dialog&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#styling-the-dialog&quot; aria-labelledby=&quot;styling-the-dialog&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Our dialog still looks quite plain, so let&amp;#39;s fix it up!&lt;/p&gt;&lt;p&gt;The following demo styles the buttons and content, but also adjusts the modal position with the following declarations which centers the dialog within the viewport. You may want to also explicitly add dimension styles depending on your dialog&amp;#39;s content - be sure to test cross-browser!&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;dialog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If needed, you can also specifically style open modal dialogs using the &lt;code&gt;:modal &lt;/code&gt;pseudo class&lt;code&gt;.&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Additionally, there is a pseudo-element available when the dialog is open which can be styled with the &lt;code&gt;::backdrop&lt;/code&gt; selector. We&amp;#39;ll darken it to a 35% opacity black and also use the property &lt;code&gt;backdrop-filter&lt;/code&gt; to create a blurred effect of the content behind the modal.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::backdrop&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 0% / 35%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;backdrop-filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;blur&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;style&gt;
    #dialog-demo-3 dialog {
  margin: auto;
  padding: 0;
  width: min(40ch, 100vw - 2rem);
  position: fixed;
  border-radius: 0.5rem;
  font-size: 1.35rem;
  background-color: white;
  border: 2px solid;
}

#dialog-demo-3 .dialog-content {
  padding: clamp(1rem, 5%, 2rem);
}

#dialog-demo-3 ::backdrop {
  background-color: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(2px);
}

#dialog-demo-3 dialog .dialog-actions {
  list-style: none;
  padding: 0;
  margin: 1rem auto 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
}

#dialog-demo-3 dialog .dialog-actions button {
  padding: 0.5em 1em;
  border: 1px solid gray;
  border-radius: 0.25rem;
  cursor: pointer;
  text-align: center;
}

#dialog-demo-3 dialog .dialog-actions li {
  margin: 0;
}

#dialog-demo-3 [data-action=confirm] {
  --button-focus: hsl(80 70% 25%);
}

#dialog-demo-3 [data-action=confirm]:is(:focus, :hover) {
  background-color: #bbe467;
}

#dialog-demo-3 [data-action=cancel]:is(:focus, :hover) {
  background-color: #f4c7be;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Final dialog with styles&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 dialog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 100vw - 2rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.35rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 .dialog-content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 ::backdrop&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.35&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;backdrop-filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;blur&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 dialog .dialog-actions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem auto 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 dialog .dialog-actions button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid gray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 dialog .dialog-actions li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 [data-action=confirm]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--button-focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;80 70% 25%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 [data-action=confirm]:is(:focus, :hover)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #bbe467&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#dialog-demo-3 [data-action=cancel]:is(:focus, :hover)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f4c7be&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dialog3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cookie-confirmation-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieTray3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#dialog-demo-3 .cookie-tray&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dialog-demo-3&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showModal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[data-action]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;confirm&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookie &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      cookie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Safari prior to 16.1 does not re-focus dialog triggering element&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      cookieTray3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookieName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cookie&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    cookieTray3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dialog&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;dialog-demo-3&quot; class=&quot;dialog-demo&quot;&gt;

  &lt;h2 id=&quot;cookie-tray-title-3&quot;&gt;Select a cookie to eat!&lt;/h2&gt;

  &lt;ul role=&quot;list&quot; class=&quot;cookie-tray&quot; tabindex=&quot;-1&quot; aria-labelledby=&quot;cookie-tray-title-3&quot;&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #1&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #2&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #3&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #4&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #5&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #6&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button type=&quot;button&quot; class=&quot;cookie&quot;&gt;&lt;img src=&quot;https://assets.codepen.io/1101822/penguin-cookie.png&quot; alt=&quot;penguin cookie #7&quot; /&gt;&lt;/button&gt;&lt;/li&gt;
  &lt;/ul&gt;

  &lt;dialog id=&quot;cookie-confirmation-3&quot;&gt;
    &lt;div class=&quot;dialog-content&quot;&gt;
      &lt;h3&gt;Cookie Selection Confirmation&lt;/h3&gt;
      &lt;p&gt;Are you sure you want to eat &lt;strong class=&quot;cookie-name&quot;&gt;&lt;/strong&gt;?&lt;/p&gt;
      &lt;ul class=&quot;dialog-actions&quot;&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;confirm&quot;&gt;Eat Cookie&lt;/button&gt;&lt;/li&gt;
        &lt;li&gt;&lt;button type=&quot;button&quot; data-action=&quot;cancel&quot;&gt;Cancel&lt;/button&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  &lt;/dialog&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const dialog3 = document.getElementById(&quot;cookie-confirmation-3&quot;);
const cookieTray3 = document.querySelector(&quot;#dialog-demo-3 .cookie-tray&quot;);

document.getElementById(&#39;dialog-demo-3&#39;).addEventListener(&quot;click&quot;, ({ target }) =&gt; {
  if (target.matches(&quot;.cookie&quot;)) {
    dialog3.querySelector(&quot;.cookie-name&quot;).textContent = target.querySelector(
      &quot;img&quot;
    ).alt;
    dialog3.showModal();
  }

  if (target.matches(&quot;[data-action]&quot;)) {
    dialog3.close();
  }

  if (target.matches(&#39;[data-action=&quot;confirm&quot;]&#39;)) {
    const cookie = document.activeElement;
    if (cookie.matches(&quot;.cookie&quot;)) {
      cookie.remove();
    } else {
      // Safari prior to 16.1 does not re-focus dialog triggering element
      const cookieName = dialog3.querySelector(&quot;.cookie-name&quot;).textContent;
      cookieTray3.querySelectorAll(&quot;.cookie img&quot;).forEach((c) =&gt; {
        if (c.alt.includes(cookieName)) {
          c.closest(&quot;.cookie&quot;).remove();
        }
      });
    }
    cookieTray3.focus();
  }
});

dialog3.addEventListener(&quot;click&quot;, ({ target }) =&gt; {
  if(target.matches(&#39;dialog&#39;)) {
    dialog3.close();
  }
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;closing-on-backdrop-interaction&quot;&gt;Closing on backdrop interaction&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#closing-on-backdrop-interaction&quot; aria-labelledby=&quot;closing-on-backdrop-interaction&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In the final styled demo, we also included the ability for clicks on the backdrop to close the dialog by detecting clicks that land on the dialog element itself. The method demonstrated works only if there is a child element that wraps the visible dialog contents and covers their full dimensions, &lt;em&gt;and&lt;/em&gt; the dialog takes up the remaining viewport space. Meaning, for example, if you add padding, ensure it&amp;#39;s on the content wrapper instead of the dialog. Our child element is &lt;code&gt;div.dialog-content&lt;/code&gt;, and the &lt;code&gt;dialog&lt;/code&gt; covers the viewport due to the margin filling the space.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; target &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dialog&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-on-dialogs&quot;&gt;Additional resources on dialogs&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/dialog/#additional-resources-on-dialogs&quot; aria-labelledby=&quot;additional-resources-on-dialogs&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While this demo covered the essentials for defining, opening, closing, and styling the &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element, there is quite a bit more to consider (like, do you even need a dialog?).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN documentation on dialog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Further definition of and &lt;a href=&quot;https://accessuse.eu/en/non-modal-dialogs.html&quot; rel=&quot;noopener noreferrer&quot;&gt;accessibility considerations for non-modal dialogs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&amp;quot;&lt;a href=&quot;https://www.scottohara.me/blog/2019/03/05/open-dialog.html&quot; rel=&quot;noopener noreferrer&quot;&gt;An open dialog&lt;/a&gt;&amp;quot; from Scott O&amp;#39;Hara shares some history and remaining considerations for using &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&amp;quot;&lt;a href=&quot;https://whistlr.info/2021/in-defence-of-dialog/&quot; rel=&quot;noopener noreferrer&quot;&gt;In defense of dialog&lt;/a&gt;&amp;quot; by Sam Thorogood covers more use cases and features&lt;/li&gt;&lt;li&gt;A thorough guide to &amp;quot;&lt;a href=&quot;https://www.smashingmagazine.com/2021/07/accessible-dialog-from-scratch/&quot; rel=&quot;noopener noreferrer&quot;&gt;Creating An Accessible Dialog from Scratch&lt;/a&gt;&amp;quot; from Kitty Giraudel explaining all the considerations you&amp;#39;d have to address if you didn&amp;#39;t use the dialog element&lt;/li&gt;&lt;li&gt;Also from Kitty is the wonderful &lt;a href=&quot;https://github.com/KittyGiraudel/a11y-dialog&quot; rel=&quot;noopener noreferrer&quot;&gt;a11y-dialog&lt;/a&gt; script which may presently be more suited for your audience if they are not using the latest browsers&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://thinkdobecreate.com/&quot;&gt;Stephanie Eckles&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/ea181894-dd65-4087-a0e7-4a67578ed25e_5t3ph.jpeg?auto=compress,format&amp;rect=0,0,500,500&amp;w=150&amp;h=150&quot; alt=&quot;Stephanie Eckles&quot; /&gt;
  &lt;p&gt;Stephanie Eckles is the author of in-depth tutorials on &lt;a href=&quot;https://moderncss.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;ModernCSS.dev&lt;/a&gt;, and creator of &lt;a href=&quot;https://stylestage.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;StyleStage.dev&lt;/a&gt;, &lt;a href=&quot;https://smolcss.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;SmolCSS.dev&lt;/a&gt;, and &lt;a href=&quot;https://11ty.rocks/&quot; rel=&quot;noopener noreferrer&quot;&gt;11ty.Rocks&lt;/a&gt;. Steph has well over a decade of webdev experience that she enjoys sharing as an author, egghead and workshop instructor, Twitch streamer, and conference speaker.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Stephanie selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Cascade Layers</title>
    <link href="https://12daysofweb.dev/2022/cascade-layers/"/>
    <updated>2022-12-17T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/cascade-layers/</id>
    <content type="html">



&lt;p&gt;Specificity is only one part of the CSS Cascade, but it&amp;#39;s the part we interact with the most often – and it can quickly become a labyrinth of twisted selectors, frustration, and swearing. That&amp;#39;s a terrible way to start the holidays! Unless we’re talking about the Jim Henson movie, which is excellent… &lt;/p&gt;&lt;p&gt;But this year, something changed in CSS. Back in February/March of 2022, all the modern web browsers released Cascade Layers – a new feature that gives you (and me) control over how our selectors interact, regardless of their specificity or code order:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* establish layer-order: last takes precedence */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; default&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; rebeccapurple&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; state&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:disabled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dimgray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; theme&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button.danger&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; maroon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button.info&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; darkslateblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;#call-to-action&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mediumvioletred&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since the &lt;code&gt;state&lt;/code&gt; layer has the highest layer priority and layers override specificity, the &lt;code&gt;disabled&lt;/code&gt; styling will always win in a conflict – even though the &lt;code&gt;theme&lt;/code&gt; styles have a higher specificity and come later in the code. We can also nest layers:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; reset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; framework&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; components&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; utilities&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; components&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; default&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; state&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* the nested components.state layer */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;:disabled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dimgray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; components.state&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* also the nested components.state layer */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; thin dashed hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And import entire stylesheets into a layer:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reset.css&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bootstrap.css&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bootstrap.external&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; bootstrap.local&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;/* anything here will override the imported code in bootstrap.external */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This can be useful on any size project for both overall architecture and individual components: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Demos&lt;/strong&gt;: I often use &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;demo&lt;/code&gt; layers when creating small code samples. Michelle Barker has a great article about doing that on her &lt;a href=&quot;https://css-irl.info/a-handy-use-for-cascade-layers/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS { In Real Life }&lt;/a&gt; blog. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;Prototypes&lt;/strong&gt;: This same approach is useful for trying something new over top of something that already exists. Put the existing code in a lower layer and prototype in a layer above. If everything in the codebase is layered, you have options! Slot something between layers, or add it to the top of the stack.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Components&lt;/strong&gt;: Working on a single component, like the buttons above, I’ll ask myself what different layers of styling I need. I find that often results in a similar set of &lt;code&gt;default&lt;/code&gt; styles, &lt;code&gt;themes&lt;/code&gt; or &lt;code&gt;modifiers&lt;/code&gt;, and &lt;code&gt;states&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Site Architecture&lt;/strong&gt;: When I start a new project, even a small personal site, I’ll often put a few generic styles in a &lt;code&gt;reset&lt;/code&gt; or &lt;code&gt;defaults&lt;/code&gt; layer – and work my way up from there. Why wait for conflicts to show up when I can avoid them from the start? This also applies to large teams and projects, where the potential for conflicts can seem to scale exponentially. Harry Roberts talks about organizing CSS in an &lt;a href=&quot;http://technotif.com/manage-large-css-projects-with-itcss/&quot; rel=&quot;noopener noreferrer&quot;&gt;Inverted Triangle&lt;/a&gt;, with different &amp;quot;layers&amp;quot; of specificity. Using the &lt;code&gt;@layer&lt;/code&gt; rule and layered imports, we can turn that implicit organizing convention into an explicit part of the cascade! &lt;/li&gt;&lt;li&gt;&lt;strong&gt;Frameworks &amp;amp; Tools&lt;/strong&gt;: Many of the existing approaches for managing specificity rely on everyone using the same strict conventions, but it’s impossible to ensure third-party code is following the same rules we use locally. Cascade layers remove the guesswork when using outside tools and let us make the priority of styles clear and consistent.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;layer-ordering&quot;&gt;Layer Ordering&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/cascade-layers/#layer-ordering&quot; aria-labelledby=&quot;layer-ordering&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Layers are stacked in the order that each layer-name first appears in the codebase, with later layer-names taking precedence over earlier layers. That means we can allow them to stack implicitly:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* the lowest layer */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* a middle layer */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* the highest layer */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or we can define the layer order explicitly by introducing layer names in order with a single list. This is recommended because it ensures a &amp;quot;single source of truth&amp;quot; for the intended order of layers:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; medium&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; high&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But there’s no magic to the list syntax – it simply introduces layer names to the stack. Since the stack is based on the &lt;em&gt;first appearance of a name&lt;/em&gt;, repeating layer names won’t change their order. This will result in exactly the same layer order as above:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* introduce the low and medium layers */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; medium&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* introduce the highest layer! */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* all these layers already exist, so nothing changes... */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; medium&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can think of this behavior as though the layers with a shared name are sorted together and merged, so the result is still:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* all the code from ‘low’ layer rules */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* all the code from ‘medium’ layer rules */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* all the code from ‘high’ layer rules */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That sorting happens independently at each layer of nesting:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* both medium &amp;amp; medium.low are introduced */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; medium.low&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium.high&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First, the top-level layers are sorted (low, medium, high), and then the nested layers are sorted inside of those:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium.low&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; medium.high&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; high&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At each level, styles that are un-nested have the highest priority - no matter where they appear in the code. In this example, all the links will be &lt;code&gt;green&lt;/code&gt;, since that selector is layered the least:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* styles not nested in a layer take priority */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; one&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* the less nesting, the the more powerful */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; brown&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; two&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Layers don’t &lt;em&gt;add priority&lt;/em&gt; the same way that &lt;code&gt;!important&lt;/code&gt; does, but instead, they &lt;em&gt;remove priority&lt;/em&gt; in relation to unlayered styles. Rather than creating an arms race to the top, they help us de-prioritize code that we should be able to override easily from somewhere else. But it’s also more nuanced than the &lt;code&gt;:where()&lt;/code&gt; selector that simply removes all specificity information from the selectors inside it. We can have both! &lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Layers help us reclaim declarative control of the &lt;em&gt;intent&lt;/em&gt; behind our CSS without removing helpful information about the specificity of selectors. We’re &lt;em&gt;managing&lt;/em&gt; the cascade instead of &lt;em&gt;removing&lt;/em&gt; it.&lt;/p&gt;&lt;p&gt;By defining a full list of layers up-front, we not only ensure a single source of truth – but it also allows us to load the rest of our layered styles in any order we want. That can be especially useful when using automated tools, like JS frameworks that only load the styles for components that are used on a given page. If all those styles are layered, and all the layer ordering is defined in advance, it doesn’t matter what order the component styles are loaded.&lt;/p&gt;&lt;p&gt;There’s a lot more we could get into here – like anonymous&lt;code&gt; &lt;/code&gt;layers and the interaction between layers and importance. I recommend checking out some other articles that get into more detail:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/css-cascade-layers/&quot; rel=&quot;noopener noreferrer&quot;&gt;A Complete Guide to CSS Cascade Layers&lt;/a&gt; (by Me)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2022/01/introduction-css-cascade-layers/&quot; rel=&quot;noopener noreferrer&quot;&gt;Getting Started With CSS Cascade Layers&lt;/a&gt; (by Stephanie Eckles)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2021/09/15/the-future-of-css-cascade-layers-css-at-layer/&quot; rel=&quot;noopener noreferrer&quot;&gt;The Future of CSS: Cascade Layers (CSS @layer)&lt;/a&gt; (by Bramus Van Damme)&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/cascade-layers/#getting-started&quot; aria-labelledby=&quot;getting-started&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Layers already have &lt;a href=&quot;https://caniuse.com/css-cascade-layers&quot; rel=&quot;noopener noreferrer&quot;&gt;very broad browser support&lt;/a&gt;, so many of us can start using them right away. There’s also a &lt;a href=&quot;https://www.oddbird.net/2022/06/21/cascade-layers-polyfill/&quot; rel=&quot;noopener noreferrer&quot;&gt;polyfill written in postCSS&lt;/a&gt;, for adding support to older browsers without any performance issues.&lt;/p&gt;&lt;p&gt;To start integrating layers onto an existing project, I work from the bottom up. Since layers &lt;em&gt;deprioritize&lt;/em&gt; styles, I start with the styles that should have the lowest priority: resets, normalization, and global defaults. Depending on the project, that might be a single layer or multiple, but the idea is the same. &lt;/p&gt;&lt;p&gt;First, we add a layer list that is easy to find at the top of our styles. It doesn’t need to be a full list, just the layers we know we’re going to need. We can even put that directly in the HTML if that helps ensure it always comes first:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* keep this before linked styles */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; reset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;path/to/styles.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we want to take that a step further, we can also use &lt;code&gt;@import&lt;/code&gt; to load our existing styles into a layer of their own: &lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@layer&lt;/span&gt; reset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; legacy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path/to/new-styles.css&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* put our layered styles in here */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path/to/old-styles.css&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;legacy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It’s great to get all our styles layered if we can because once we have un-layered styles, there’s nowhere higher to go. By making sure everything is in a layer, we have total flexibility to add new styles above or below what’s already there.&lt;/p&gt;&lt;p&gt;Once the low-priority styles are layered, I would focus on any external styles that a site relies on: design systems, component libraries, and third-party frameworks. Those are the most likely source of specificity frustration, and moving them into layers will make them much easier to manage.&lt;/p&gt;&lt;p&gt;I use Harry Roberts’ Inverted Triangle as a guide. Where he recommends allowing specificity to grow slowly with each implied layer of a project:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/5336e339-e384-4a51-adcd-802fb46a6de9_gradual-specificity.png?auto=compress,format&quot; alt=&quot;A line graph where the y-axis is specificity and the x-axis is lines of code, and vertical cross sections represent groups of styles where generic has lowest specificity and lines of code and the line trends upwards through elements, objects, components, and utilities where both axes are highest.&quot; /&gt;&lt;/p&gt;&lt;p&gt;I break off one layer at a time, from lowest to highest, making it an explicit layer in the cascade: &lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/1b14f8b8-9964-493e-8ebf-7a5610e8dc83_broken-layer-of-specificity.png?auto=compress,format&quot; alt=&quot;The same line graph but now the first part of the line - &amp;quot;generic&amp;quot; - where specificity and lines of code are lowest has a break from the rest of the upward-trending line.&quot; /&gt;&lt;/p&gt;&lt;p&gt;As each layer is given an explicit place in the cascade, we have more freedom to use a range of specificity within that layer. We no longer need to constrain ourselves to single-class BEM selectors or carefully remove specificity everywhere possible! Each layer is self-contained, and we can rely on specificity to help work things out inside each layer:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/061559e6-206e-4cab-aeb4-258f548702cf_completely-layered-specificity.png?auto=compress,format&quot; alt=&quot;Now the line graph is segemented within each veritcal section and shows a more gradual increase between each section for specificity and lines of code, demonstrating how each layer is now self-contained.&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;unleash-the-selectors&quot;&gt;Unleash the Selectors!&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/cascade-layers/#unleash-the-selectors&quot; aria-labelledby=&quot;unleash-the-selectors&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Selectors are one of the most powerful (and under-utilized) features in CSS – allowing us to target elements for styling based on a whole range of details. We can use them to &lt;a href=&quot;https://benmyers.dev/blog/semantic-selectors/&quot; rel=&quot;noopener noreferrer&quot;&gt;represent state&lt;/a&gt;, &lt;a href=&quot;https://adrianroselli.com/2021/06/using-css-to-enforce-accessibility.html&quot; rel=&quot;noopener noreferrer&quot;&gt;enforce accessibility patterns&lt;/a&gt;, &lt;a href=&quot;http://alistapart.com/article/axiomatic-css-and-lobotomized-owls/&quot; rel=&quot;noopener noreferrer&quot;&gt;manage content flow&lt;/a&gt; and &lt;a href=&quot;https://moderncss.dev/guide-to-advanced-css-selectors-part-one/#practical-applications-for-the-general-sibling-combinator&quot; rel=&quot;noopener noreferrer&quot;&gt;element spacing&lt;/a&gt;, &lt;a href=&quot;https://lea.verou.me/2020/07/the-cicada-principle-revisited-with-css-variables/&quot; rel=&quot;noopener noreferrer&quot;&gt;incorporate randomness&lt;/a&gt;, establish &lt;a href=&quot;https://www.smashingmagazine.com/2019/07/css-custom-properties-cascade/#selectors-and-parameters&quot; rel=&quot;noopener noreferrer&quot;&gt;component parameters&lt;/a&gt;, and &lt;a href=&quot;https://front-end.social/@mia/109490835236966986&quot; rel=&quot;noopener noreferrer&quot;&gt;so much more&lt;/a&gt;. Most importantly, selectors allow us to define abstracted style patterns that can be written in one place and reused across components.&lt;/p&gt;&lt;p&gt;CSS is designed to be &lt;a href=&quot;https://adactio.com/journal/18982&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;em&gt;systemic&lt;/em&gt; and &lt;em&gt;declarative&lt;/em&gt;&lt;/a&gt; – giving the browser information about why different styles might be applied in different situations. While we can apply the same styles to &lt;code&gt;.contact–submit__focus&lt;/code&gt; or &lt;code&gt;.contact [type=&amp;#39;submit&amp;#39;]:focus-visible&lt;/code&gt;, the former is a meaningless string of characters that we have to define and apply ourselves (often with JS), while the latter conveys detailed information that the browser can use to apply styles on our behalf. The result is more resilient, performant, and readable code.&lt;/p&gt;&lt;p&gt;Selectors are there for a reason, and we should take advantage of their full potential. Instead, we’ve been restricting what selectors are allowed and enforcing more and more limited conventions in an attempt to somehow &lt;em&gt;avoid the cascade&lt;/em&gt;. &lt;strong&gt;But the cascade is unavoidable; it’s the core of the language.&lt;/strong&gt; There will always be selector conflicts, and there will always be an algorithm to resolve those conflicts. All we’ve been doing is denying ourselves access to one of the coolest features on the web platform. &lt;/p&gt;&lt;p&gt;I hope that cascade layers can help to turn that trend around.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://www.miriamsuzanne.com/&quot;&gt;Miriam Suzanne&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/7d3d287a-dee5-4968-80cd-8ff4599432cf_miriam.jpeg?auto=compress,format&amp;rect=188,37,335,335&amp;w=150&amp;h=150&quot; alt=&quot;Miriam Suzanne&quot; /&gt;
  &lt;p&gt;I make music with &lt;a href=&quot;https://www.miriamsuzanne.com/orgs/teacup-gorilla/&quot; rel=&quot;noopener noreferrer&quot;&gt;Teacup Gorilla&lt;/a&gt;, theater with &lt;a href=&quot;https://www.miriamsuzanne.com/orgs/grapefruit-lab/&quot; rel=&quot;noopener noreferrer&quot;&gt;Grapefruit Lab&lt;/a&gt;, and web software with &lt;a href=&quot;https://www.miriamsuzanne.com/orgs/oddbird/&quot; rel=&quot;noopener noreferrer&quot;&gt;OddBird&lt;/a&gt;. I’m an Invited Expert on the &lt;a href=&quot;https://www.miriamsuzanne.com/orgs/csswg/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS Working Group&lt;/a&gt;, a core contributor to the &lt;a href=&quot;https://www.miriamsuzanne.com/orgs/sass/&quot; rel=&quot;noopener noreferrer&quot;&gt;Sass&lt;/a&gt; language, a regular conference &lt;a href=&quot;https://www.miriamsuzanne.com/speaking/&quot; rel=&quot;noopener noreferrer&quot;&gt;speaker&lt;/a&gt;, and a lover of yarn-related crafts.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Miriam selected &lt;strong&gt;&lt;a href=&quot;https://www.coloradofreedomfund.org/&quot;&gt;Colorado Freedom Fund&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.coloradofreedomfund.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/901c7b47-dfe4-4678-9c4f-93a991a88670_Screen+Shot+2022-12-11+at+12.03.26+PM.png?auto=compress,format&quot; alt=&quot;Colorado Freedom Fund&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;While people with money can pay their way out of jail, poor people don’t have that luxury. CFF is an abolitionist-led non-profit, and a member of the National Bail Fund Network – paying cash bail for our neighbors trapped in Colorado cages.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>FormData API</title>
    <link href="https://12daysofweb.dev/2022/formdata-api/"/>
    <updated>2022-12-16T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/formdata-api/</id>
    <content type="html">



&lt;p&gt;Historically, getting all of the data from a form into a single object was a bit difficult, but modern techniques make it a lot easier.&lt;/p&gt;&lt;p&gt;Let’s dig in!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-formdata-object&quot;&gt;Creating a FormData object&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#creating-a-formdata-object&quot; aria-labelledby=&quot;creating-a-formdata-object&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;FormData&lt;/code&gt; object provides an easy way to serialize form fields into key/value pairs.&lt;/p&gt;&lt;p&gt;You can use the new &lt;code&gt;FormData()&lt;/code&gt; constructor to create a new &lt;code&gt;FormData&lt;/code&gt; object, passing in the form to serialize as an argument. &lt;/p&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Important! &lt;/strong&gt;Form fields must have a &lt;code&gt;name&lt;/code&gt; attribute to be included in the object. Otherwise, they&amp;#39;re skipped. The &lt;code&gt;id&lt;/code&gt; property doesn&amp;#39;t count.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;For example, let’s imagine you have a form that looks like this.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Title&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Go to the beach&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Body&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;textarea&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Soak up the sun and swim in the ocean.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;textarea&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Submit&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To create a &lt;code&gt;FormData&lt;/code&gt; object, you would pass the form into the new &lt;code&gt;FormData()&lt;/code&gt; constructor, like this.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Get the form&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;form&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Get all field data from the form&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// returns a FormData object&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;form&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;FormData&lt;/code&gt; object is an iterable.&lt;/p&gt;&lt;p&gt;You can loop through it using a &lt;code&gt;for...of&lt;/code&gt; loop. Each entry is an array of key/value pairs.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// logs...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// [&quot;title&quot;, &quot;Go to the beach&quot;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// [&quot;body&quot;, &quot;Soak up the sun and swim in the ocean.&quot;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// [&quot;userId&quot;, &quot;1&quot;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; entry &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/OJEPRvR?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo for you to play with.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can also use &lt;a href=&quot;https://gomakethings.com/destructuring-in-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;array destructuring&lt;/a&gt; to assign the key and value to their own variables within the &lt;code&gt;for...of&lt;/code&gt; loop.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// logs &quot;title&quot;, &quot;Go to the beach&quot;, etc.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/NWzPRMj?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s another demo, with array destructuring.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;getting-setting-and-updating-formdata-values&quot;&gt;Getting, setting, and updating FormData values&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#getting-setting-and-updating-formdata-values&quot; aria-labelledby=&quot;getting-setting-and-updating-formdata-values&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;FormData&lt;/code&gt; object has a handful of methods that you can use to get, set, and update values.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;FormData.get()&lt;/code&gt; method accepts the name of the field as an argument and returns its value. Here, we would get the value of the &lt;code&gt;[name=&amp;quot;title&amp;quot;]&lt;/code&gt; field.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// returns &quot;Go to the beach&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;title&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you had multiple fields with the same name, you might instead use the &lt;code&gt;FormData.getAll()&lt;/code&gt; method. It returns an array of values instead.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// returns [&quot;Go to the beach&quot;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; titles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;title&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can use the &lt;code&gt;FormData.set()&lt;/code&gt; method to add a new value to your &lt;code&gt;FormData&lt;/code&gt; object. If an entry with that name already exists, the &lt;code&gt;FormData.set()&lt;/code&gt; method overwrites it.&lt;/p&gt;&lt;p&gt;Pass in a name and value as arguments.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Add a new entry, &quot;date&quot;, to the FormData object&lt;/span&gt;&lt;br /&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;date&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2022-12-25&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Overwrite the &quot;id&quot; entry&lt;/span&gt;&lt;br /&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;42&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;FormData.append()&lt;/code&gt; method adds an additional value for an existing entry if one with that name already exists. If not, it creates a new entry.&lt;/p&gt;&lt;p&gt;Pass in a name and value as arguments.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Adds an additional &quot;id&quot; value&lt;/span&gt;&lt;br /&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;123&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Creates a new entry, &quot;tags&quot;&lt;/span&gt;&lt;br /&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;tags&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;vacations&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;FormData.delete()&lt;/code&gt; method deletes all values for an entry.&lt;/p&gt;&lt;p&gt;Pass in the name of the item to delete as an argument.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Deletes the &quot;body&quot; entry&lt;/span&gt;&lt;br /&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/ExRaNYz?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo with all of the methods for manipulating FormData values.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;It’s worth noting that all of these changes happen to the &lt;code&gt;FormData&lt;/code&gt; object and its values, not the actual form element or its fields.&lt;/p&gt;&lt;p&gt;None of these methods will update the state of the DOM or UI.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;convenience-methods&quot;&gt;Convenience methods&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#convenience-methods&quot; aria-labelledby=&quot;convenience-methods&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;FormData&lt;/code&gt; object also provides a few convenient methods for working with form data.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;FormData.has()&lt;/code&gt; method can be used to check if a FormData object contains an entry with a specific name.&lt;/p&gt;&lt;p&gt;It returns a &lt;code&gt;boolean: true&lt;/code&gt; if the entry exists and false if it does not.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// returns true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; hasID &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;FormData.keys()&lt;/code&gt; method returns an iterator with all of the keys in the FormData object.&lt;/p&gt;&lt;p&gt;You can loop them with &lt;a href=&quot;https://gomakethings.com/the-for...of-loop-in-vanilla-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a for…of loop&lt;/a&gt;, or convert them into an array using the &lt;code&gt;Array.from()&lt;/code&gt; method.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Loop through all keys&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Convert to an array&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/gOKbLPW?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo of the FormData.keys() method.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The &lt;code&gt;FormData.values()&lt;/code&gt; method returns an iterator with all of the values in the &lt;code&gt;FormData&lt;/code&gt; object.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Loop through&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; val &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Convert to an array&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/OJEPbpO?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo of the FormData.values() method.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;serializing-formdata-into-an-object&quot;&gt;Serializing FormData into an object&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#serializing-formdata-into-an-object&quot; aria-labelledby=&quot;serializing-formdata-into-an-object&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You might intend to pass your &lt;code&gt;FormData&lt;/code&gt; object along to an API.&lt;/p&gt;&lt;p&gt;While some APIs will accept a &lt;code&gt;FormData&lt;/code&gt; object in its native form, many require you to pass along an object instead.&lt;/p&gt;&lt;p&gt;If your form does &lt;em&gt;not&lt;/em&gt; contain multiple fields with the same name, you can use the &lt;code&gt;Object.fromEntries()&lt;/code&gt; method to convert your &lt;code&gt;FormData&lt;/code&gt; object into a plain object (&lt;code&gt;{}&lt;/code&gt;).&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// returns...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;//   title: &quot;Go to the beach&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;//   body: &quot;Soak up the sun and swim in the ocean&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;//   id: &quot;1&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; serialized &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromEntries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, if your form has multiple fields with the same name, only the value of the last field with that name will appear in the object.&lt;/p&gt;&lt;p&gt;We instead need to loop through each entry with a &lt;code&gt;for...of&lt;/code&gt; loop and add it to an object.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To account for multiple fields with the same name, we need to check if the key already exists in the obj. &lt;/p&gt;&lt;p&gt;If it does, we want to convert it to an array and &lt;code&gt;Array.push()&lt;/code&gt; the new value into it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you find yourself doing this often, I’ve put together &lt;a href=&quot;https://vanillajstoolkit.com/helpers/serialize/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a helper method you can use&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Once you have your object, you can pass it into the &lt;code&gt;JSON.stringify()&lt;/code&gt; method to send along to an API.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; stringified &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;serializing-formdata-into-a-query-string&quot;&gt;Serializing FormData into a query string&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#serializing-formdata-into-a-query-string&quot; aria-labelledby=&quot;serializing-formdata-into-a-query-string&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Some APIs instead require data as a query string.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;key=some+value&amp;amp;another-key=some+other+value&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To convert our &lt;code&gt;FormData&lt;/code&gt; object into a query string, we’ll use the &lt;code&gt;URLSearchParams()&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;It provides methods for getting, setting, and modifying query string values and has a similar API as the &lt;code&gt;FormData&lt;/code&gt; object.&lt;/p&gt;&lt;p&gt;First, we’ll use the new &lt;code&gt;URLSearchParams()&lt;/code&gt; constructor to create our query string object.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, we’ll loop through each item in our &lt;code&gt;FormData&lt;/code&gt; object with a &lt;code&gt;for…of&lt;/code&gt; loop, and use the &lt;code&gt;URLSearchParams.append()&lt;/code&gt; method to add the &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt; to our query string.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;URLSearchParams.append()&lt;/code&gt; method automatically encodes the value for us.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; val&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, we can use the &lt;code&gt;URLSearchParams.toString()&lt;/code&gt; method to get the actual query string.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://codepen.io/cferdinandi/pen/abKzBQN?editors=1111&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Here’s a demo of the URLSearchParams object.&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/formdata-api/#wrapping-up&quot; aria-labelledby=&quot;wrapping-up&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We covered a lot in this article, so let’s quickly wrap up what we learned.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;To get a serialized object of your form fields, pass the form element into the new &lt;code&gt;FormData()&lt;/code&gt; constructor.&lt;/li&gt;&lt;li&gt;You can get, set, and update values using the &lt;code&gt;get()&lt;/code&gt;, &lt;code&gt;getAll()&lt;/code&gt;, &lt;code&gt;set()&lt;/code&gt;, and &lt;code&gt;delete()&lt;/code&gt; methods.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;has()&lt;/code&gt;, &lt;code&gt;keys()&lt;/code&gt;, and &lt;code&gt;values()&lt;/code&gt; methods provide an easy way to check if a value exists and get all of the keys or values from a &lt;code&gt;FormData&lt;/code&gt; object.&lt;/li&gt;&lt;li&gt;You can serialize form values to a plain object using the &lt;code&gt;Object.fromEntries()&lt;/code&gt; method or by looping through each entry and adding it to an object.&lt;/li&gt;&lt;li&gt;You can serialize form values into a query string using a &lt;code&gt;for…of&lt;/code&gt;  loop and the &lt;code&gt;URLSearchParams&lt;/code&gt; API.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you enjoyed this, you might also like my &lt;a href=&quot;https://gomakethings.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Daily Developer Tips newsletter&lt;/a&gt;. Each weekday, I send out a short email on how to build a simpler, more resilient web.&lt;/p&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://gomakethings.com/&quot;&gt;Chris Ferdinandi&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/f9ac5856-fc58-47e3-9af7-bbe2b9247e11_chris.jpeg?auto=compress,format&amp;rect=0,0,400,400&amp;w=150&amp;h=150&quot; alt=&quot;Chris Ferdinandi&quot; /&gt;
  &lt;p&gt;Chris Ferdinandi helps people learn vanilla JavaScript, and believes there’s a simpler, more resilient way to make things for the web. His &lt;a href=&quot;https://gomakethings.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;developer tips newsletter&lt;/a&gt; is read by thousands of developers each weekday. Learn more at &lt;a href=&quot;https://gomakethings.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GoMakeThings.com&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Chris selected &lt;strong&gt;&lt;a href=&quot;https://www.feedingamerica.org/&quot;&gt;Feeding America&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.feedingamerica.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-increase-contrast&quot; src=&quot;https://nvlupin.blob.core.windows.net/images/van/FAM/FAM/1/87084/images/themes/logo.svg&quot; alt=&quot;Feeding America&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Feeding America is the largest charity working to end hunger in the United States. We partner with food banks, food pantries, and local food programs to bring food to people facing hunger. We advocate for policies that create long-term solutions to hunger.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>CSS image()</title>
    <link href="https://12daysofweb.dev/2022/css-image/"/>
    <updated>2022-12-15T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/css-image/</id>
    <content type="html">



&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-is-the-image-function&quot;&gt;What is the image() function?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#what-is-the-image-function&quot; aria-labelledby=&quot;what-is-the-image-function&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we declare a &lt;code&gt;background-image&lt;/code&gt;, we use the &lt;code&gt;url()&lt;/code&gt; function to tell the browser where it can find the image.&lt;/p&gt;&lt;p&gt;While very useful, &lt;code&gt;url()&lt;/code&gt; has some limitations that can sometimes result in hacky solutions, so as part of the &lt;a href=&quot;https://www.w3.org/TR/css-images-4/&quot; rel=&quot;noopener noreferrer&quot;&gt;level 4 spec for CSS Image Values and Replaced Content&lt;/a&gt;, the working group has introduced the &lt;code&gt;image()&lt;/code&gt; function.&lt;/p&gt;&lt;p&gt;While at first glance it is very similar to &lt;code&gt;url()&lt;/code&gt;, it opens up some new doors as it can allow us to define:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Image fragments&lt;/strong&gt;. These allow us to define a specific part of the image that should be visible rather than the entire image (this is also being added to &lt;code&gt;url()&lt;/code&gt; but with a slight drawback which we’ll talk about).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The directionality of the image&lt;/strong&gt;. This might sound strange but could prove very useful in some situations.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A solid color to use as a fallback&lt;/strong&gt; if the image fails to load, or even to define the background itself &lt;strong&gt;&lt;code&gt;without&lt;/code&gt;&lt;/strong&gt; an image. On first glance, this sounds a little pointless, but it might be my favorite use case for &lt;code&gt;image()&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;aside role=&quot;note&quot; data-type=&quot;alert&quot;&gt;&lt;p&gt;As of the time of writing, the level 4 spec of CSS Image Values and Replaced Content is still only a working draft. This means things are still subject to change, and, as of the time of writing, no browser currently supports &lt;code&gt;image()&lt;/code&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-very-basics-of-image&quot;&gt;The very basics of image()&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#the-very-basics-of-image&quot; aria-labelledby=&quot;the-very-basics-of-image&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;image()&lt;/code&gt; function can accept three optional values:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A tag for image directionality (either &lt;code&gt;ltr&lt;/code&gt; or &lt;code&gt;rtl&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;An image source&lt;/li&gt;&lt;li&gt;A color&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Because everything is optional, it can look a lot like &lt;code&gt;url()&lt;/code&gt; at first:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.keeping-it-simple&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.webp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;image-fragments&quot;&gt;Image fragments&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#image-fragments&quot; aria-labelledby=&quot;image-fragments&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we provide the URL for the image, we can add a media fragment identifier to display only a portion of the image rather than the entire thing.&lt;/p&gt;&lt;p&gt;We do this by supplying an &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinate, which are the starting point, followed by a &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;We do this by appending the information after the URL with a &lt;code&gt;#xywh=&lt;/code&gt; followed by the values we want to use for the starting coordinates, width, and height.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.hero&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=150,50,500,300&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the example above, we would start in the top-left corner, move 150 pixels across and 50 pixels down, and then select the region that would be &lt;code&gt;500px&lt;/code&gt; wide by &lt;code&gt;300px&lt;/code&gt; tall from that starting point.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/f23d1a52-b881-43d3-9fbd-5ad70e47480d_image-fragment.png?auto=compress,format&quot; alt=&quot;A photo of a puppy wearing glasses and looking at a computer has an overlay showing how it could be cropped using the image fragments noted in the previous paragraph.&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;use-cases-for-image-fragments&quot;&gt;Use cases for image fragments&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#use-cases-for-image-fragments&quot; aria-labelledby=&quot;use-cases-for-image-fragments&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One thing that might come to mind is being able to use one image and crop it in different ways within a media query. However, this means you are loading in a larger image than is required, and you might be better served using the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element, which allows for different sources based on the viewport size.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Learn about &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/&quot; rel=&quot;noopener noreferrer&quot;&gt;the picture element and other image display options&lt;/a&gt; from Day 8, 2021!&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;If you are using the same image multiple times within a page and need to crop it in different ways, image fragments would be a lot easier than working with &lt;code&gt;background-size&lt;/code&gt; and &lt;code&gt;background-position&lt;/code&gt; and would allow you to load in one single image rather than multiple different versions of it.&lt;/p&gt;&lt;p&gt;Another use case would be image sprites, where we can simplify how we have traditionally done them using &lt;code&gt;background-position&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.icon-1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/icon-sprite.png#xywh=0,0,16,16&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.icon-2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/icon-sprite.png#xywh=16,0,16,16&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.icon-3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/icon-sprite.png#xywh=32,0,16,16&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;using-pixels-or-percentage&quot;&gt;Using pixels or percentage&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#using-pixels-or-percentage&quot; aria-labelledby=&quot;using-pixels-or-percentage&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we define the fragment, the default units used are pixels, but we can explicitly tell the browser to use percentages instead by including &lt;code&gt;percent:&lt;/code&gt; before the coordinates.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.pixel-based-fragment-1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=20,30,500,300&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.pixel-based-fragment-2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=pixel:20,30,500,300&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.percentage-based-fragment&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=percent:10,10,70,80&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When we do this, &lt;em&gt;all&lt;/em&gt; of the coordinates will be a percentage.&lt;/p&gt;&lt;p&gt;That means in the example above, the class &lt;code&gt;.percentage-based-fragment&lt;/code&gt; would show &lt;code&gt;70%&lt;/code&gt; of the total width and &lt;code&gt;80%&lt;/code&gt; of the total height of the original image, starting &lt;code&gt;10%&lt;/code&gt; across and &lt;code&gt;10%&lt;/code&gt; down.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;the-url-function-and-image-fragments&quot;&gt;The url() function and image fragments&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#the-url-function-and-image-fragments&quot; aria-labelledby=&quot;the-url-function-and-image-fragments&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Image fragments have also been added to the &lt;code&gt;url()&lt;/code&gt; function.&lt;/p&gt;&lt;p&gt;If a browser doesn’t support &lt;code&gt;image() &lt;/code&gt;it simply won’t load the image, whether or not there is a fragment.&lt;/p&gt;&lt;p&gt;When using an image fragment within a &lt;code&gt;url()&lt;/code&gt;, if a browser doesn’t support image fragments, it will still load in the image provided in a &lt;code&gt;url()&lt;/code&gt;, but the fragment will be ignored, resulting in the entire image loading in.&lt;/p&gt;&lt;p&gt;Depending on the situation—such as with image sprites—this could be problematic.&lt;/p&gt;&lt;p&gt;Instead, we could provide a fallback as a &lt;code&gt;url()&lt;/code&gt; for browsers that do not support fragments.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.with-fallback-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;images/my-fallback.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=20,30,500,300&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;directionality&quot;&gt;Directionality&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#directionality&quot; aria-labelledby=&quot;directionality&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With the rise of logical properties, it is now easier than ever to deal with different writing directions.&lt;/p&gt;&lt;p&gt;The idea of an image changing directions might seem a little strange, as most images you use shouldn’t be flipped when switching between a left-to-right or right-to-left language.&lt;/p&gt;&lt;p&gt;If we omit a direction tag, then the image is considered to have no directionality, and the writing direction will have no impact on the image.&lt;/p&gt;&lt;p&gt;If you have images or icons that denote directionality, such as an arrow on a bullet list, this feature could be super handy!&lt;/p&gt;&lt;p&gt;Taking that arrow example, you might do something like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.arrow-list&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&#39;arrow.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would work fine until you switch the writing direction, which would result in this:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/d7dc04ae-8a75-40de-b1cf-bce4bd7406fd_directionality-before.png?auto=compress,format&quot; alt=&quot;A list in a left-to-right language and a right-to-left language where the arrow image points the wrong way (to the right) for the right-to-left language.&quot; /&gt;&lt;/p&gt;&lt;p&gt;Using the &lt;code&gt;image()&lt;/code&gt; function, we can add directionality to the image by indicating it before the URL with either &lt;code&gt;ltr&lt;/code&gt; or &lt;code&gt;rtl&lt;/code&gt; for &lt;strong&gt;left-to-right&lt;/strong&gt; or &lt;strong&gt;right-to-left&lt;code&gt;.&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;This defines the original direction of the image, telling the browser that if the writing direction changes from what we have defined, the image should follow that switch.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.arrow-list&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ltr &lt;span class=&quot;token string&quot;&gt;&#39;arrow.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/8b0bc2f1-fa71-49dc-a549-3f1fbfdbe32d_directionality-after.png?auto=compress,format&quot; alt=&quot;The same lists as before but now the arrow image for the right-to-left image correctly points towards the list text (to the left).&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-fallback&quot;&gt;Creating a fallback&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#creating-a-fallback&quot; aria-labelledby=&quot;creating-a-fallback&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;When we declare a &lt;code&gt;background-image&lt;/code&gt; it is a good idea to provide a solid color fallback in case the image doesn’t load so that we can ensure any text that would be on top of the image is still readable.&lt;/p&gt;&lt;p&gt;Using &lt;code&gt;image()&lt;/code&gt;, we can do this by simply providing a color along with our URL.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.with-fallback-color&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;images/my-image.jpg#xywh=20,30,500,300&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #123456&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Being able to declare a fallback color is already very handy, but it also opens up another possibility that I’m very excited by.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;tinting-an-image&quot;&gt;Tinting an image&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#tinting-an-image&quot; aria-labelledby=&quot;tinting-an-image&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A common complaint about background images is that there is no easy way to reduce their opacity.&lt;/p&gt;&lt;p&gt;Either we need to open up some editing software or use a pseudo-element as a layer between our background and the content.&lt;/p&gt;&lt;p&gt;This is because if we have a &lt;code&gt;background-color&lt;/code&gt; and a &lt;code&gt;background-image&lt;/code&gt;, the image is always on top of the color.&lt;/p&gt;&lt;p&gt;We can use a &lt;code&gt;background-blend-mode&lt;/code&gt; to blend the two, but this can be hit-and-miss, and the effect can change drastically from one image to another.&lt;/p&gt;&lt;p&gt;One useful thing we can do with &lt;code&gt;background-image&lt;/code&gt; is stack multiple images on top of one another, and because &lt;code&gt;image()&lt;/code&gt; allows us to declare a solid color, that color can be part of that stack of images.&lt;/p&gt;&lt;p&gt;We can use this to tint an image by putting the top layer in our stack as a solid color with a reduced opacity.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.tinted-bg-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;210 47% 20% / .75&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;images/my-image.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With this, we can tint an image quickly with any color we want, including the same color we’ve used as the background to simply make the image look like it has a lower opacity on it.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.tinted-bg-image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;210 47% 20% / .75&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;images/my-image.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.fake-low-opacity-bg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 100% / .8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;images/my-image.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/a851aea0-7ba3-465e-b987-b053f639fb7b_tinted-image.png?auto=compress,format&quot; alt=&quot;Comparison of three images with a text overlay. In the original, the text does not have enough contrast, and the subsequent two images show using image() to tint the image light or dark to afford enough contrast.&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;wrap-up&quot;&gt;Wrap up&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#wrap-up&quot; aria-labelledby=&quot;wrap-up&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;CSS seems to be evolving at a faster pace than ever, with a few big features, like &lt;code&gt;:has()&lt;/code&gt; and &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;container queries&lt;/a&gt; getting a lot of attention (with good reason, they’re amazing).&lt;/p&gt;&lt;p&gt;While I’m looking forward to a lot of the big new things as well, things like &lt;code&gt;image()&lt;/code&gt; often go under the radar but end up being those little things that improve how CSS works at its core.&lt;/p&gt;&lt;p&gt;By being able to easily bring in image fragments instead of having to fight with &lt;code&gt;background-position&lt;/code&gt; and &lt;code&gt;background-size&lt;/code&gt;, providing fallback colors, and enabling layers of images and colors, those of us who author CSS are gaining a lot of small quality-of-life things that, over time, we’re sure to simply take for granted.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/css-image/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-images-4/#image-notation&quot; rel=&quot;noopener noreferrer&quot;&gt;The working draft&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/image/image&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://www.kevinpowell.co/&quot;&gt;Kevin Powell&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/40ae6422-2346-4999-ade4-229fc89a6fa7_kevin.webp?auto=compress,format&amp;rect=0,0,600,600&amp;w=150&amp;h=150&quot; alt=&quot;Kevin Powell&quot; /&gt;
  &lt;p&gt;Hi there! My name is Kevin and I&amp;#39;m a CSS Evangelist. I absolutely love CSS, and I want to help new front-end devs enjoy learning it, and help seasoned vets see how great it really is. Most of my content is over on YouTube, but I also stream on Twitch, and write articles every now and then as well, and create courses for learning CSS.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Kevin selected &lt;strong&gt;&lt;a href=&quot;https://www.fondationstejustine.org/&quot;&gt;CHU Sainte-Justine Foundation&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.fondationstejustine.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;img-dark-filter&quot; src=&quot;https://www.fondationstejustine.org/app/themes/ste-justine-corpo-theme/public/images/logo_fr_voir_grand.svg&quot; alt=&quot;CHU Sainte-Justine Foundation&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;Support CHU Sainte-Justine in its pursuit of excellence and its commitment to providing children and mothers with one of the highest levels of health care in the world, now and in the future.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>View Transitions API</title>
    <link href="https://12daysofweb.dev/2022/view-transitions-api/"/>
    <updated>2022-12-14T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/view-transitions-api/</id>
    <content type="html">



&lt;p&gt;Using creative animations can provide enjoyable and memorable user experiences in many ways:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Animating loaders while data is being loaded&lt;/li&gt;&lt;li&gt;Micro-interactions to reveal or hide sections of pages&lt;/li&gt;&lt;li&gt;Increase the perceived performance of a site or application&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;State changes, more specifically page transitions, are rather difficult to animate, however. There are several third-party JavaScript packages for managing page transitions, but there has not been a solid native solution to this as of yet.&lt;/p&gt;&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/groups/wg/css&quot; rel=&quot;noopener noreferrer&quot;&gt;W3C CSS Working Group&lt;/a&gt; is currently working on a &lt;a href=&quot;https://drafts.csswg.org/css-view-transitions-1/&quot; rel=&quot;noopener noreferrer&quot;&gt;draft specification&lt;/a&gt; for a new native API for page transitions called &lt;strong&gt;View Transitions.&lt;/strong&gt; &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser Compatibility&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/view-transitions-api/#browser-compatibility&quot; aria-labelledby=&quot;browser-compatibility&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;At the time of writing, the &lt;strong&gt;View Transitions API&lt;/strong&gt; is unsupported in all major browsers as it is an extremely experimental feature within Chrome and is subject to change.&lt;/p&gt;&lt;p&gt;To enable this feature: you must be on Chrome (Canary) 109 or greater and enable the &lt;strong&gt;View Transitions&lt;/strong&gt; feature flag at &lt;code&gt;chrome://flags/#view-transition&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;basic-example&quot;&gt;Basic example&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/view-transitions-api/#basic-example&quot; aria-labelledby=&quot;basic-example&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A very basic example of View Transitions follows this pattern:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;viewTransition&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;startViewTranstion&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// handle unsupported browsers&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startViewTransition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;thingToTransition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Inside the &lt;code&gt;.startViewTransition()&lt;/code&gt; method, you can pass in any type of DOM manipulation you want. You aren’t limited to just page transitions here; you can also move elements from one parent element to another, add or remove elements, toggle classes, and more. &lt;/p&gt;&lt;p&gt;Once the &lt;code&gt;.startViewTransition()&lt;/code&gt; method is called, the View Transitions API creates snapshots of both the current state and the state that is being transitioned to, then performs the transition between the two. &lt;/p&gt;&lt;p&gt;The default animation used in View Transitions is a crossfade animation, which looks something like this:&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/1-crossfade.mp4&quot;&gt;&lt;/video&gt;&lt;p&gt;While the transition is occurring, a set of pseudo-elements is provided that we can use to customize the transition. &lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;customizing-transitions&quot;&gt;Customizing Transitions&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/view-transitions-api/#customizing-transitions&quot; aria-labelledby=&quot;customizing-transitions&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The pseudo-elements provided by the View Transitions API are organized into a tree, like so:&lt;/p&gt;&lt;pre&gt;::view-transition
└─ ::view-transition-group(root)
    └─ ::view-transition-image-pair(root)
       ├─ ::view-transition-old(root)
       └─ ::view-transition-new(root)&lt;/pre&gt;&lt;p&gt;These pseudo-elements can be used inside CSS to create more customized animations to occur during the transition. An important thing to note here is &lt;code&gt;root&lt;/code&gt; refers to the default transition. Currently, this means everything being transitioned is the root transition. We can have multiple transitions by setting view transition names, where we can apply different animations to different transitions (more on that in a bit). &lt;/p&gt;&lt;p&gt;A simple test customization is changing the animation duration via CSS, like so:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::view-transition-old(root),&lt;br /&gt;::view-transition-new(root)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will slow down the crossfade animation to 5 seconds:&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/2-animation-duration.mp4&quot;&gt;&lt;/video&gt;&lt;p&gt;While the transition is slowed down, you can really see what is happening here: &lt;code&gt;::view-transition-old(root)&lt;/code&gt; is fading out the current state, while &lt;code&gt;::view-transition-new(root)&lt;/code&gt; is fading the new state in.&lt;/p&gt;&lt;p&gt;A smoother transition might be expanding the image to full size after clicking on a thumbnail. To do this, we need to set a few other CSS properties on the elements that are targeted during the transition.&lt;/p&gt;&lt;p&gt;There are actually multiple elements being transitioned here: the thumbnails on the gallery page and the full-sized image on the image page.&lt;/p&gt;&lt;p&gt;In our example, the thumbnail images are selected by targeting &lt;code&gt;.gallery-item img&lt;/code&gt;. We will need to apply the &lt;code&gt;contain: layout&lt;/code&gt; property to these thumbnail images like so:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.gallery-item img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* ...other styles */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;contain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; layout&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;contain&lt;/code&gt; property indicates that the element is as independent as possible from the rest of the page. The layout value isolates the element’s internal layout, preventing anything from the outside from affecting its internal layout. This is helpful as the layout of the element being transitioned needs to remain intact during the transition.&lt;/p&gt;&lt;p&gt;For the full-sized image, we will give it the &lt;code&gt;contain: layout&lt;/code&gt; property as well, but we also want to apply a unique name to the view transition. We can do so by giving it the CSS property &lt;code&gt;view-transition-name&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.full-size img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-transition-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; full-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;contain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; layout&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With just this CSS, we have actually accomplished the effect we are aiming for!&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/3-expanding-animation.mp4&quot;&gt;&lt;/video&gt;&lt;p&gt;Applying a transition name will separate the transitions a bit, giving us a little more flexibility regarding how each transition can be animated. Now we can target both the &lt;code&gt;root&lt;/code&gt; transition as well as the &lt;code&gt;full-size&lt;/code&gt; transition when applying animations:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::view-transition-old(root),&lt;br /&gt;::view-transition-new(root)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* CSS animations styles for root */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;::view-transition-old(full-size),&lt;br /&gt;::view-transition-new(full-size)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* CSS animations styles for full-size */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Completed transition:&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/4-completed.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;further-information&quot;&gt;Further Information&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/view-transitions-api/#further-information&quot; aria-labelledby=&quot;further-information&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;You will need Chrome Canary to test this with, but feel free to check out the source for the demo on &lt;a href=&quot;https://github.com/mrtrimble/view-transitions-example&quot; rel=&quot;noopener noreferrer&quot;&gt;Github&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;This is a super exciting feature, and I’m looking forward to when we can implement this on production sites. &lt;/p&gt;&lt;p&gt;For more information on &lt;strong&gt;View Transitions&lt;/strong&gt;, check out Jake Archibald’s article on the topic below, as it is currently the main reference for the API.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;other-resources&quot;&gt;Other Resources:&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/view-transitions-api/#other-resources&quot; aria-labelledby=&quot;other-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/shared-element-transitions-for-spas/&quot; rel=&quot;noopener noreferrer&quot;&gt;Smooth and simple page transitions with the View Transitions API &lt;/a&gt;by Jake Archibald&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-view-transitions-1/&quot; rel=&quot;noopener noreferrer&quot;&gt;View Transitions Module Draft Specification&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/WICG/view-transitions/blob/main/explainer.md&quot; rel=&quot;noopener noreferrer&quot;&gt;View Transitions Explainer&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://ryantrimble.com/&quot;&gt;Ryan Trimble&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/a96141bd-7738-4dcc-8607-fcdb5b7f9e25_ryan.jpeg?auto=compress,format&amp;rect=0,0,400,400&amp;w=150&amp;h=150&quot; alt=&quot;Ryan Trimble&quot; /&gt;
  &lt;p&gt;User Experience and User Interface Developer for Ritter Insurance Marketing, living on a creek in central Pennsylvania. I like to write code and make people happy!&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Ryan selected &lt;strong&gt;&lt;a href=&quot;https://www.thetrevorproject.org/&quot;&gt;The Trevor Project&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.thetrevorproject.org/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://images.prismic.io/12daysofwebdev/0b2035b5-5854-498d-8478-d170a486cc05_Screen+Shot+2022-12-09+at+5.20.49+PM.png?auto=compress,format&quot; alt=&quot;The Trevor Project&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The Trevor Project’s mission is to end suicide among LGBTQ young people.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>New Viewport Units</title>
    <link href="https://12daysofweb.dev/2022/new-viewport-units/"/>
    <updated>2022-12-13T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2022/new-viewport-units/</id>
    <content type="html">



&lt;p&gt;Once upon a time, web designers worried about browser window sizes—was the site supposed to be 640x480, 800x600, 1024x768? Even, dare we hope, 1280x960? And we fretted over whether a scrollbar would show or not, because that might throw off the horizontal layout space by a few pixels.&lt;/p&gt;&lt;p&gt;But then came Responsive Web Design, where we freed ourselves from those pixel plateaus and plunged headlong into the world of infinite diversity in infinite device displays. Once we were setting breakpoints and writing styles for whole strata of screen sizes at a time, our past preoccupations with a single scrollbar seemed silly.&lt;/p&gt;&lt;p&gt;There was a serpent in the Garden of E-mail, though. If you’ve used a mobile web browser in the past decade or so, you know they have a tendency to slide the URL bar and navigation buttons in from the top and bottom of the viewport when needed, and away when not. It’s a nice way to balance the desire for maximum reading space and access to browser chrome. But it raises the question: &lt;em&gt;what defines the viewport&lt;/em&gt;? Is it the display space the browser UI hidden? The space between them when they appear? Both? Neither?&lt;/p&gt;&lt;p&gt;This matters because of viewport units like vh (viewport height) or vb (viewport block). If you set an image to be 100vh tall, trying to fill out the height of the viewport, will it actually fill the whole display? Will it shrink a bit to fit between the browser bars when they appear, or will it be overlapped? Should it instead be the minimum available height when the browser UI is visible, thus leaving it shorter than the display when the chrome is gone?&lt;/p&gt;&lt;p&gt;What if you want access to all those behaviors?&lt;/p&gt;&lt;p&gt;Enter the large, small, and dynamic viewports.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/714b4e4d-0d28-467c-9571-6946ab487e35_viewports2.png?auto=compress,format&quot; alt=&quot;A diagram shows the difference between the &amp;quot;large viewport&amp;quot; and &amp;quot;small viewport&amp;quot;, where the large occupies the space when dynamic UI is hidden and the small occupies the space when dynamic UI is visible. Large units are displayed as lvh and lvb for the height/block direction, and lvw and lvi for the width/inline direction. Small units are displayed as svh and svh for the height/block direction, and svw and svi for the width/inline direction.&quot; /&gt;&lt;figcaption&gt;A diagram shows the difference between the &amp;quot;large viewport&amp;quot; and &amp;quot;small viewport&amp;quot;, where the large occupies the space when dynamic UI is hidden and the small occupies the space when dynamic UI is visible. Large units are displayed as lvh and lvb for the height/block direction, and lvw and lvi for the width/inline direction. Small units are displayed as svh and svh for the height/block direction, and svw and svi for the width/inline direction.&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;large-viewport&quot;&gt;Large Viewport&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/#large-viewport&quot; aria-labelledby=&quot;large-viewport&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;strong&gt;large viewport&lt;/strong&gt; is the viewport without any dynamic browser interface showing. On a mobile device, that would generally be the entire display surface, so setting an element to be &lt;code&gt;100lvh&lt;/code&gt; and &lt;code&gt;100lvw&lt;/code&gt; means it will be the same size as the device display.&lt;/p&gt;&lt;p&gt;A good use case for the large viewport is an illustration or “cover page” at the beginning of an article, sized to cover some or all of the entire viewport, where it’s okay if some parts are overlapped by the browser interface. A three-quarter-screen page might get CSS something like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article &gt; header&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100lvw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 75lvh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cover-illo.jpg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, if you plan to use the large viewport units, you should probably make sure your coding font makes clear the difference between 1 (one) and l (lowercase L), or else you might think you’ve specified &lt;code&gt;1,001 vw&lt;/code&gt; or &lt;code&gt;751 vh&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;small-viewport&quot;&gt;Small Viewport&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/#small-viewport&quot; aria-labelledby=&quot;small-viewport&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Anyway, the &lt;strong&gt;small viewport&lt;/strong&gt; is the viewport with all the dynamic browser interface showing. Therefore, setting an element to be &lt;code&gt;100svh&lt;/code&gt; and &lt;code&gt;100svw&lt;/code&gt; means it will be exactly sized so that it will fit inside all the dynamic browser interfaces.&lt;/p&gt;&lt;p&gt;A good use case for the small viewport would be sizing a dialog so that no part of it can ever be overlapped by the browser interface, which is important for dialogs that have “X to dismiss” or similar. So you might style such a thing like this:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.warning&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100svh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100svh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;dynamic-viewport&quot;&gt;Dynamic Viewport&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/#dynamic-viewport&quot; aria-labelledby=&quot;dynamic-viewport&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you want something to resize itself as the browser interface elements appear and disappear, you size with regard to the &lt;strong&gt;dynamic viewport&lt;/strong&gt;. An element &lt;code&gt;100dvh&lt;/code&gt; and &lt;code&gt;100dvw&lt;/code&gt; will be exactly the same size as whatever part of the viewport is visible between browser interface elements. If there are none, the dynamic viewport is the same size as the large viewport. If all the browser interface is visible, the dynamic viewport is equal to the small viewport.&lt;/p&gt;&lt;p class=&quot;key&quot;&gt;Keep in mind that as browser interface elements appear and disappear, the dynamic viewport will change from moment to moment, which means the exact length of the &lt;code&gt;dvh&lt;/code&gt; and &lt;code&gt;dvw&lt;/code&gt; units will change from moment to moment. This, in turn, means anything sized using those units will change, sort of like an interface-linked animation.&lt;/p&gt;&lt;p&gt;Picture it: a user starts to scroll a page on a mobile device, causing the URL bar and navigation bar to slide away. Anything sized using dynamic viewport units will resize even as the page is scrolling and the viewport is changing. This could be a significant performance hit, and even if not, the visual effect could be unsettling, potentially triggering users with vestibular disorders or epilepsy.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-new-viewport-units&quot;&gt;Using New Viewport Units&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2022/new-viewport-units/#using-new-viewport-units&quot; aria-labelledby=&quot;using-new-viewport-units&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Although these may seem very mobile- or at least handheld-centric, these units may become more handy for desktop and embedded contexts over time. Desktop browsers may become more like their mobile counterparts in terms of setting dynamic UI elements, and embedded-display browsers on things like home appliances or auto dashboard displays (which one &lt;em&gt;could&lt;/em&gt; think of as mobile devices, in their own way) could very well use dynamic UI conventions.&lt;/p&gt;&lt;p&gt;Given all that, it’s definitely worth getting comfortable with these new viewports and their units. And here they are, spread out in a holiday table for you.&lt;/p&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Viewport&lt;/th&gt;
&lt;th&gt;Large&lt;/th&gt;
&lt;th&gt;Small&lt;/th&gt;
&lt;th&gt;Dynamic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;height&lt;/td&gt;
&lt;td&gt;lvh&lt;/td&gt;
&lt;td&gt;svh&lt;/td&gt;
&lt;td&gt;dvh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;block axis&lt;/td&gt;
&lt;td&gt;lvb&lt;/td&gt;
&lt;td&gt;svb&lt;/td&gt;
&lt;td&gt;dvb&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;width&lt;/td&gt;
&lt;td&gt;lvw&lt;/td&gt;
&lt;td&gt;svw&lt;/td&gt;
&lt;td&gt;dvw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inline axis&lt;/td&gt;
&lt;td&gt;lvi&lt;/td&gt;
&lt;td&gt;svi&lt;/td&gt;
&lt;td&gt;dvi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minimum axis&lt;/td&gt;
&lt;td&gt;lvmin&lt;/td&gt;
&lt;td&gt;svmin&lt;/td&gt;
&lt;td&gt;dvmin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;maximum axis&lt;/td&gt;
&lt;td&gt;lvmax&lt;/td&gt;
&lt;td&gt;svmax&lt;/td&gt;
&lt;td&gt;dvmax&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You can use these &lt;a href=&quot;https://caniuse.com/viewport-unit-variants&quot; rel=&quot;noopener noreferrer&quot;&gt;new viewport units&lt;/a&gt; today as a progressive enhancement by also including the stable unit in the corresponding direction, example:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.cover-dynamic-viewport&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100dvi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100dvb&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://meyerweb.com/&quot;&gt;Eric A. Meyer&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/8d036699-2569-471f-86f6-0faaeb9f0899_eric.jpeg?auto=compress,format&amp;rect=0,1,199,199&amp;w=150&amp;h=150&quot; alt=&quot;Eric A. Meyer&quot; /&gt;
  &lt;p&gt;Eric has been working with the web since late 1993 and is an internationally recognized expert on the subjects of HTML, CSS, and web standards.  A widely read author, he is technical lead at Rebecca’s Gift, a 501(c)(3) non-profit organization dedicated to providing healing family vacations after the death of a child; and is, along with &lt;a href=&quot;https://meyerweb.com/speakers/jeffreyzeldman/&quot; rel=&quot;noopener noreferrer&quot;&gt;Jeffrey Zeldman&lt;/a&gt;, co-founder of &lt;a href=&quot;http://aneventapart.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;An Event Apart&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;
&lt;div id=&quot;donation&quot;&gt;&lt;p&gt;Eric selected &lt;strong&gt;&lt;a href=&quot;https://www.stbaldricks.org/hero-funds/rebeccameyer/&quot;&gt;Rebecca’s Gift&lt;/a&gt;&lt;/strong&gt; for an honorary donation of $50 which has been matched by &lt;a href=&quot;https://netlify.com/&quot; class=&quot;netlify&quot;&gt;&lt;img src=&quot;https://12daysofweb.dev/img/netlify.svg&quot; alt=&quot;Netlify&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
      &lt;a href=&quot;https://www.stbaldricks.org/hero-funds/rebeccameyer/&quot; class=&quot;org&quot;&gt;&lt;img class=&quot;&quot; src=&quot;https://www.stbaldricks.org/photo/fund/26/large&quot; alt=&quot;Rebecca’s Gift&quot; /&gt;&lt;/a&gt;
      &lt;p&gt;The money raised by Rebecca’s Fund will be added to the St. Baldrick’s efforts to fund promising research in the prevention of tumor reemergence.&lt;/p&gt;
      &lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Container Queries</title>
    <link href="https://12daysofweb.dev/2021/container-queries/"/>
    <updated>2021-12-24T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/container-queries/</id>
    <content type="html">



&lt;p&gt;&lt;strong&gt;Updated September 2022&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;CSS Container Queries are an upcoming way to move beyond media queries that are tied to the viewport and instead will enable us to modify an element&amp;#39;s behavior based on the container it&amp;#39;s within. This has been a requested feature for many years, with developers desiring to change an element based on its own width. However, the in-progress spec will allow querying for other property values - including &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/&quot;&gt;from custom properties&lt;/a&gt; - to alter a component.&lt;/p&gt;&lt;p&gt;Back in May, I wrote &amp;quot;&lt;a href=&quot;https://www.smashingmagazine.com/2021/05/complete-guide-css-container-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;A Primer on CSS Container Queries&lt;/a&gt;&amp;quot; and since that time the spec has moved into being &lt;a href=&quot;https://drafts.csswg.org/css-contain-3/&quot; rel=&quot;noopener noreferrer&quot;&gt;a Public Working Draft&lt;/a&gt; and some of the syntax has been updated.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;enabling-container-queries&quot;&gt;Enabling container queries&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#enabling-container-queries&quot; aria-labelledby=&quot;enabling-container-queries&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you would like to view the demos in this article and experiment with container queries yourself, you&amp;#39;ll need to be on a supporting browser:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;All nightly versions&lt;/li&gt;&lt;li&gt;Chromium 105+&lt;/li&gt;&lt;li&gt;Safari 16+&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;defining-containment&quot;&gt;Defining containment&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#defining-containment&quot; aria-labelledby=&quot;defining-containment&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Given that the container query spec is not final, keep in mind that the syntax discussed in this post is at risk of changing.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Why talk about container queries if they aren&amp;#39;t stable? Because the CSS Working Group and browser makers need your feedback! If you find a bug, have a feature request, or want to know the current status, check out &lt;a href=&quot;https://github.com/w3c/csswg-drafts/projects/18&quot; rel=&quot;noopener noreferrer&quot;&gt;the css-contain issues on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;A key concept of container queries is that you must explicitly define which elements allow containment. Then you query against those containers which allow you to affect the properties of its children. This can be a bit of a gotcha, which we&amp;#39;ll look at in action a bit later.&lt;/p&gt;&lt;p&gt;At minimum for queries intended to be based on width, containment is defined by setting &lt;code&gt;container-type: inline-size&lt;/code&gt; on a containing element.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Optionally, you can also name your container with &lt;code&gt;container-name &lt;/code&gt;which is useful if you have several layers of containment so that you can be more explicit about which queries affect elements.&lt;/p&gt;&lt;p&gt;Both type and name can be defined using the shorthand &lt;code&gt;container&lt;/code&gt; property, where the name is first and separated from the type by a forward slash.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; main / inline-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;key&quot;&gt;If a container query is applied to an element that has no defined containing ancestor, the query will fail to apply. In other words - there is no default fallback containment on either the &lt;code&gt;body&lt;/code&gt; or &lt;code&gt;html&lt;/code&gt; elements.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;defining-a-container-query&quot;&gt;Defining a container query&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#defining-a-container-query&quot; aria-labelledby=&quot;defining-a-container-query&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now that we know how to apply containment to an element, we&amp;#39;re ready to actually write a container query!&lt;/p&gt;&lt;p&gt;Eventually, we&amp;#39;ll be able to not just query based on size but also style properties (at time of writing, querying on style was not yet supported).&lt;/p&gt;&lt;p&gt;With our current &lt;code&gt;container-type&lt;/code&gt; using &lt;code&gt;inline-size&lt;/code&gt;, we&amp;#39;ll write our first query. We&amp;#39;ll also explicitly query against our named container of &amp;quot;main&amp;quot;. If we left off the name, this query would be against the &lt;code&gt;h2&lt;/code&gt;&amp;#39;s nearest ancestor with containment.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; main &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 40ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oh, and what&amp;#39;s that? A new syntax for the query definition using math comparisons? Oh yes! &lt;a href=&quot;https://www.w3.org/TR/mediaqueries-5/#mq-range-context&quot; rel=&quot;noopener noreferrer&quot;&gt;This is an update&lt;/a&gt; that will be coming to &amp;quot;old fashioned&amp;quot; media queries against the viewport as well! Thanks, CSS Working group 🥰&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;demo-of-responding-to-size-containment&quot;&gt;Demo of responding to size containment&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#demo-of-responding-to-size-containment&quot; aria-labelledby=&quot;demo-of-responding-to-size-containment&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s put the pieces we&amp;#39;ve learned so far together. For myself, so far treating container queries similar to the idea of &amp;quot;mobile first&amp;quot; has made the most sense in developing my &amp;quot;breakpoints&amp;quot; across component states. By which I mean styling for the narrowest view as the default then handling updates for larger widths via the container queries.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Container queries can absolutely start being used today as a progressive enhancement. If you plan to do that, starting with the narrowest width may not be the best &amp;quot;fallback&amp;quot; for your context so you may adjust from this strategy.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;We&amp;#39;ll be using CSS grid and grid areas to adjust a card layout, and particularly to update the card image location and aspect ratio.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;narrow-container-card-styles&quot;&gt;Narrow container card styles&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#narrow-container-card-styles&quot; aria-labelledby=&quot;narrow-container-card-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For the narrowest expected container, our card elements simply stack and the image is set at &lt;code&gt;aspect-ratio: 4/3&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Our initial HTML is very simple:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://source.unsplash.com/V7SKRhXskv8/400x300&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Container Queries Rule&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;style&gt;
    .card {
  display: grid;
  gap: 1rem;
  margin: 5vh auto;
  padding: 1rem;
  border-radius: 0.5rem;
  box-shadow: 0 .25rem 0.5rem -.15rem hsla(0 0% 0% / 55%);
}

.card &gt; * {
  margin: 0;
}

.card img {
  max-width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  border-radius: inherit;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of narrowest card styles&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5vh auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 .25rem 0.5rem -.15rem &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 0% / 55%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4/3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;card&quot;&gt;
  &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
  &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
  &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;This may look a little strange if you are viewing this on a larger viewport because the card currently has no width constraints.&lt;/p&gt;&lt;p&gt;I mentioned we&amp;#39;d be updating the card layout using CSS grid template areas, and we want those to apply based on container queries. Let&amp;#39;s see what happens if we add containment to the card class, and then add a container query to define the grid template areas.&lt;/p&gt;
    

    
    &lt;style&gt;
    .card--contained {
  container-type: inline-size;
}

@container (width &gt;= 30ch) {
  .card--contained {
    grid-template-areas: &quot;image title&quot; &quot;content content&quot;;
  }
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of applying containment to .card&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card--contained&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 30ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card--contained&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image title&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content content&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;card card--contained&quot;&gt;
  &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
  &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
  &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;If you&amp;#39;re in a browser with container query enabled, you might be surprised that no change has occurred... unless you remember the &amp;quot;gotcha&amp;quot; I noted earlier.&lt;/p&gt;&lt;p&gt;Since an element can&amp;#39;t change its properties within a container query unless it has an ancestor with containment, our attempt at updating the display of the card was unsuccessful.&lt;/p&gt;&lt;p&gt;In this case, we need to add a wrapping element to provide containment. Let&amp;#39;s make that adjustment to our HTML and then adjust the styles. Note that the demo styles require a bit of extra scoping to be able to show the change from the previous state.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card-container&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://source.unsplash.com/V7SKRhXskv8/400x300&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Container Queries Rule&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;style&gt;
    .card-container {
  container-type: inline-size;
  margin: 0;
}

@container (width &gt;= 30ch) {
  .card-container .card {
    grid-template-areas: &quot;image title&quot; &quot;content content&quot;;
    grid-auto-columns: 33% 1fr;
    align-items: center;
  }
  
  .card-container .card p {
    grid-area: content;
  }
  
  .card-container .card img {
    aspect-ratio: 1;
  }
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of adding a wrapping element with containment&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;container-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 30ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container .card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image title&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content content&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-auto-columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 33% 1fr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container .card p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container .card img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;card-container&quot;&gt;
  &lt;div class=&quot;card&quot;&gt;
    &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
    &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
    &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;Hooray, our query was successfully applied!&lt;/p&gt;&lt;p&gt;You can probably assess that we can improve the layout here even more for larger widths, so let&amp;#39;s do that. We&amp;#39;ll adjust the template areas so the image takes up the left third and the title and content share the remaining inline space. There is no change needed for our HTML.&lt;/p&gt;
    

    
    &lt;style&gt;
    @container (width &gt;= 60ch) {
  .card-container--large .card {
    grid-template-areas: &quot;img title&quot; &quot;img content&quot;;
  }
  
  .card-container--large .card img {
    grid-area: img;
  }
 
  .card-container--large .card h3 {
    align-self: end;
  }
  
  .card-container--large .card p {
    align-self: start;
  }
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of the &quot;large&quot; card container query&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 60ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container--large .card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;img title&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;img content&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container--large .card img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; img&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container--large .card h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;align-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container--large .card p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;align-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;card-container card-container--large&quot;&gt;
  &lt;div class=&quot;card&quot;&gt;
    &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
    &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
    &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;multi-card-layout&quot;&gt;Multi-card layout&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#multi-card-layout&quot; aria-labelledby=&quot;multi-card-layout&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now, as a standalone card the variations still aren&amp;#39;t too impressive, and you may be thinking the container query hasn&amp;#39;t added much value.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s add a few more cards and place them within a flexbox-based grid layout.&lt;/p&gt;
    

    
    &lt;style&gt;
    .card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.card-grid .card-container {
  flex: 1 1 30ch;
}

.card-grid .card {
  margin: 0;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of cards within a flexible grid layout&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card-grid&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card-grid .card-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1 1 30ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card-grid .card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;ul class=&quot;card-grid&quot;&gt;
  &lt;li class=&quot;card-container card-container--large&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li class=&quot;card-container card-container--large&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/ekthrVC_DVs/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li class=&quot;card-container card-container--large&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/0Sd2qqU5soQ/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;If you are unable to use a supporting browser on your device, here&amp;#39;s a preview of what these cards look like within the grid. Because of how we&amp;#39;ve setup our flexbox behavior, when there is enough room the third card can expand fullwidth. So in this preview we see the first and second card have taken on our medium container size and the third has taken on the large container size.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/b3c6fce4-43ae-4cb1-b020-4a326ff146d3_Screen+Shot+2021-12-23+at+9.56.32+PM.png?auto=compress,format&quot; alt=&quot;The three card elements arranged in the flexbox grid where the first and second share half of the top row and the third card taks up the full third row. The medium size cards show the card image and title sharing a row, and the large card shows the image taking up the left third and the title and content sharing the right two-thirds.&quot; /&gt;&lt;/p&gt;
    

    

    

    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;container-query-units&quot;&gt;Container query units&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#container-query-units&quot; aria-labelledby=&quot;container-query-units&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Along with the main spec is the inclusion of a new set of units related to the container size.&lt;/p&gt;&lt;p&gt;To me, one of the most exciting applications for these is responsive typography. Today, we can create what&amp;#39;s often called &lt;a href=&quot;https://moderncss.dev/generating-font-size-css-rules-and-creating-a-fluid-type-scale/&quot; rel=&quot;noopener noreferrer&quot;&gt;fluid typography&lt;/a&gt; using the CSS function &lt;code&gt;clamp()&lt;/code&gt; and viewport units. But those are not contextually ideal for smaller components like the cards we created since they are tied to the viewport.&lt;/p&gt;&lt;p&gt;We can take our cards one step further by applying the relevant &lt;a href=&quot;https://drafts.csswg.org/css-contain-3/#container-lengths&quot; rel=&quot;noopener noreferrer&quot;&gt;container query unit&lt;/a&gt; as a swap for what we previously used a viewport unit for to make our card typography responsive.&lt;/p&gt;&lt;p&gt;We&amp;#39;re still using &lt;code&gt;clamp()&lt;/code&gt; to provide a range of acceptable values, and the container unit we&amp;#39;ve selected is &lt;code&gt;cqi&lt;/code&gt; which represents increments of &lt;code&gt;1%&lt;/code&gt; of the container&amp;#39;s inline size.&lt;/p&gt;
    

    
    &lt;style&gt;
    .card-container--units .card h3 {
  font-size: clamp(1.25rem, 3cqi + 1rem, 2.5rem);
}

.card-container--units .card p {
  font-size: clamp(.9rem, .5cqi + 1rem, 1.5rem);
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of using container units for responsive typography&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card-container--units .card h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.25rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 3cqi + 1rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.card-container--units .card p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.9rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; .5cqi + 1rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;ul class=&quot;card-grid&quot;&gt;
  &lt;li class=&quot;card-container card-container--large card-container--units&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/V7SKRhXskv8/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li class=&quot;card-container card-container--large card-container--units&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/ekthrVC_DVs/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li class=&quot;card-container card-container--large card-container--units&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
      &lt;img src=&quot;https://source.unsplash.com/0Sd2qqU5soQ/400x300&quot; alt=&quot;&quot; /&gt;
      &lt;h3&gt;Container Queries Rule&lt;/h3&gt;
      &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?&lt;/p&gt;
    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-on-css-container-queries&quot;&gt;Additional resources on CSS container queries&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/container-queries/#additional-resources-on-css-container-queries&quot; aria-labelledby=&quot;additional-resources-on-css-container-queries&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;I hope this overview has sparked your interest in container queries! It&amp;#39;s definitely the CSS feature I&amp;#39;m most hopeful will make it into more browsers in 2022.&lt;/p&gt;&lt;p&gt;If you&amp;#39;d like more of a background on what problem container queries are trying to solve and some additional considerations, be sure to read &lt;a href=&quot;https://www.smashingmagazine.com/2021/05/complete-guide-css-container-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;my original primer&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The primary spec author for container queries is Miriam Suzanne, and I highly recommend &lt;a href=&quot;https://www.miriamsuzanne.com/speaking/responsive-components/&quot; rel=&quot;noopener noreferrer&quot;&gt;watching one of her presentations&lt;/a&gt; that covers not just CQ but also the other specs she&amp;#39;s working on that are very exciting: layers and scope. I also encourage you to read her additional &lt;a href=&quot;https://css.oddbird.net/rwd/query/explainer/&quot; rel=&quot;noopener noreferrer&quot;&gt;explainer doc&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries&quot; rel=&quot;noopener noreferrer&quot;&gt;There is already a page on MDN&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;More examples of ways to use container queries (note that not all may have the updated syntax):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Miriam&amp;#39;s &lt;a href=&quot;https://codepen.io/collection/XQrgJo&quot; rel=&quot;noopener noreferrer&quot;&gt;collection of CodePens&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Ahmad Shadeed&amp;#39;s &lt;a href=&quot;https://ishadeed.com/article/say-hello-to-css-container-queries/&quot; rel=&quot;noopener noreferrer&quot;&gt;overview with practical applications&lt;/a&gt;&lt;/li&gt;&lt;li&gt;And even more links to checkout in Stu Robson&amp;#39;s repo &lt;a href=&quot;https://github.com/sturobson/Awesome-Container-Queries&quot; rel=&quot;noopener noreferrer&quot;&gt;Awesome-Container-Queries&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Form Autocomplete</title>
    <link href="https://12daysofweb.dev/2021/form-autocomplete/"/>
    <updated>2021-12-23T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/form-autocomplete/</id>
    <content type="html">



&lt;p&gt;Howdy! &lt;a href=&quot;https://benmyers.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;Ben&lt;/a&gt; here.&lt;/p&gt;&lt;p&gt;This month, deep in the throes of shopping for last-minute gifts online, I&amp;#39;ve encountered a lot of forms. The thing about forms is they can get repetitive fast. Name, email, phone number, address, billing details… It might be Christmastime, but it&amp;#39;s feeling more like Groundhog&amp;#39;s Day!&lt;/p&gt;&lt;p&gt;To that end, let&amp;#39;s talk about some handy web form APIs that can make forms much more comfortable to fill out: &lt;strong&gt;autocomplete&lt;/strong&gt; and &lt;strong&gt;virtual keyboard options&lt;/strong&gt;.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;autocomplete&quot;&gt;Autocomplete&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#autocomplete&quot; aria-labelledby=&quot;autocomplete&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;This holiday season, give your users the gift of not having to fill out forms themselves! With the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element&amp;#39;s &lt;code&gt;autocomplete&lt;/code&gt; attribute, we can tell our user&amp;#39;s browsers which common bits of form data we&amp;#39;re expecting, and the browser will give users the chance to populate those fields instantly using values from their previous submissions.&lt;/p&gt;&lt;p&gt;This is commonly used to fill out contact info, such as:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Name:&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we need, we could get individual piece of our user&amp;#39;s name with &lt;code&gt;autocomplete=&amp;quot;honorific-prefix&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;given-name&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;additional-name&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;family-name&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;honorific-suffix&amp;quot;&lt;/code&gt;, and &lt;code&gt;&amp;quot;nickname&amp;quot;&lt;/code&gt; (but beware of &lt;a href=&quot;https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/&quot; rel=&quot;noopener noreferrer&quot;&gt;misconceptions about how names work&lt;/a&gt;):&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;prefix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Honorific Prefix (for example, Ms., Mx., Dr.):&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;prefix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;honorific-prefix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;firstName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    First Name:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;firstName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;given-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;middleName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Middle Name:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;middleName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;additional-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lastName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Last Name:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lastName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;family-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;suffix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Suffix (for example, Jr., III, PhD):&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;suffix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;honorific-suffix&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;nickname&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Nickname:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;nickname&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;nickname&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can help the user autofill their address:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Name:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;addressLine1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Address Line 1:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;addressLine1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;address-line1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;addressLine2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Address Line 2:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;addressLine2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;address-line2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;city&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    City:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;city&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;address-level2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    State:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;address-level1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zip&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Postal Code/ZIP Code:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zip&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;postal-code&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;country&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Country:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;country&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;country-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;… Or their billing information!&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Cardholder Name:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cc-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardNumber&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Card Number:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardNumber&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cc-number&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardExpiryMonth&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Expiration Month:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardExpiryMonth&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cc-exp-month&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardExpiryYear&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Expiration Year:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardExpiryYear&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cc-exp-year&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardSecurityCode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    Card Security Code:&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cardSecurityCode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cc-csc&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;autocomplete&lt;/code&gt; has so many options to give your users a boost when they&amp;#39;re filling out forms on your site. You can autofill their birthdays (with &lt;code&gt;&amp;quot;bday&amp;quot;&lt;/code&gt; — or &lt;code&gt;&amp;quot;bday-day&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;bday-month&amp;quot;&lt;/code&gt;, and &lt;code&gt;&amp;quot;bday-year&amp;quot;&lt;/code&gt;), their phone numbers (&lt;code&gt;&amp;quot;tel&amp;quot;&lt;/code&gt;), their username (&lt;code&gt;&amp;quot;username&amp;quot;&lt;/code&gt;), and more! It&amp;#39;s worth &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete&quot; rel=&quot;noopener noreferrer&quot;&gt;going to MDN to see them all&lt;/a&gt;!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;autocomplete-for-one-time-codes&quot;&gt;Autocomplete for One-Time Codes&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#autocomplete-for-one-time-codes&quot; aria-labelledby=&quot;autocomplete-for-one-time-codes&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While I&amp;#39;m just listing out possible autocomplete values, I&amp;#39;m gonna pause here to geek out about one option I&amp;#39;ve found especially convenient: &lt;code&gt;autocomplete=&amp;quot;one-time-code&amp;quot;&lt;/code&gt;. This particular value is supported by iOS and Android, and it&amp;#39;s meant for when a user is trying to sign in to your site from their phone and they receive a text message with a six-digit one-time code to log in. The user&amp;#39;s mobile browser can get that six-digit code from their text messages and fill out the field automatically, so that the user doesn&amp;#39;t have to switch between their browser and their texts. &lt;a href=&quot;https://web.dev/sms-otp-form/#autocomplete%22one-time-code%22&quot; rel=&quot;noopener noreferrer&quot;&gt;See `&amp;quot;one-time-code&amp;quot; in action here!&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The web is really cool, sometimes.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;autocomplete-and-accessibility&quot;&gt;Autocomplete and Accessibility&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#autocomplete-and-accessibility&quot; aria-labelledby=&quot;autocomplete-and-accessibility&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Autocomplete aids accessibility! For instance, for people with motor disabilities and chronic illnesses, who might find filling out large forms difficult or painful, autocomplete can really save time and &lt;a href=&quot;https://en.wikipedia.org/wiki/Spoon_theory&quot; rel=&quot;noopener noreferrer&quot;&gt;spoons&lt;/a&gt;. It&amp;#39;s also less taxing for people with memory issues or anyone whose disabilities make it difficult to read or write.&lt;/p&gt;&lt;p&gt;In fact, using autocomplete values when available is required for meeting &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html&quot; rel=&quot;noopener noreferrer&quot;&gt;WCAG Success Criterion 1.3.5 - Identify Input Purpose&lt;/a&gt;. This criterion specifically states that an input&amp;#39;s purpose can be &amp;quot;programmatically determined&amp;quot; which is exactly what autocomplete helps do. The criterion also notes that a proper label helps in this goal, for example in clarifying what type of email is required, such as business or personal or someone else&amp;#39;s.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;virtual-keyboard-modes&quot;&gt;Virtual Keyboard Modes&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#virtual-keyboard-modes&quot; aria-labelledby=&quot;virtual-keyboard-modes&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In addition to &lt;code&gt;autocomplete=&amp;quot;one-time-code&amp;quot;&lt;/code&gt;, mentioned above, we devs have more ways to show love to forms in mobile browsers. Specifically, we can give the user&amp;#39;s mobile browsers hints as to tweak the on-screen virtual keyboard interface that pops up.&lt;/p&gt;&lt;p&gt;The primary way we tweak this is through the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;&amp;#39;s type: &lt;code&gt;&amp;lt;input type=&amp;quot;text&amp;quot; /&amp;gt;&lt;/code&gt; shows the user&amp;#39;s normal keyboard, &lt;code&gt;&amp;lt;input type=&amp;quot;email&amp;quot;&amp;gt;&lt;/code&gt; shows an adjusted keyboard which displays the &lt;code&gt;@&lt;/code&gt; key more prominently, &lt;code&gt;&amp;lt;input type=&amp;quot;number&amp;quot;&amp;gt;&lt;/code&gt; shows a numeric keyboard, and so forth. Adding the &lt;code&gt;type&lt;/code&gt; attribute also hints to the browser that it should apply a bit of validation to those fields before submitting the form.&lt;/p&gt;&lt;p&gt;Thanks to the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element&amp;#39;s &lt;code&gt;inputmode&lt;/code&gt; and &lt;code&gt;enterkeyhint&lt;/code&gt; attributes, we can tweak the virtual keyboards further:&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;inputmode&quot;&gt;inputmode&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#inputmode&quot; aria-labelledby=&quot;inputmode&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode&quot; rel=&quot;noopener noreferrer&quot;&gt;inputmode&lt;/a&gt;&lt;/code&gt; can be used to change the virtual keyboard&amp;#39;s layout. It typically highlights certain keys for certain kinds of content like type does, but it doesn&amp;#39;t enable field validation like type will. Your &lt;code&gt;inputmode&lt;/code&gt; options are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;text&lt;/code&gt; - the default keyboard&lt;/li&gt;&lt;li&gt;&lt;code&gt;search&lt;/code&gt; - for search queries&lt;/li&gt;&lt;li&gt;&lt;code&gt;email&lt;/code&gt; - for email addresses&lt;/li&gt;&lt;li&gt;&lt;code&gt;url&lt;/code&gt; - for URLs&lt;/li&gt;&lt;li&gt;&lt;code&gt;numeric&lt;/code&gt; - for numbers without decimal points&lt;/li&gt;&lt;li&gt;&lt;code&gt;decimal&lt;/code&gt; - for numbers with decimal points&lt;/li&gt;&lt;li&gt;&lt;code&gt;tel&lt;/code&gt; - for phone numbers&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here&amp;#39;s a look at the difference between &amp;quot;numeric&amp;quot; and &amp;quot;decimal&amp;quot; on my iPhone.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/3e84479e-8031-40d8-a659-eb0690919271_decimal-numeric.png?auto=compress,format&quot; alt=&quot;Two screenshots from an iPhone with virtual keyboard expanded. The first screenshot has a numeric input focused and shows a numeric keyboard, while the second has a decimal input focused and shows a numeric keyboard with the addition of a decimal key.&quot; /&gt;&lt;/p&gt;&lt;p&gt;The difference is pretty subtle — the decimal example shows a decimal point key in the bottom-left corner of the keypad. It&amp;#39;s a little thing, but it can help guide users into supplying the right information.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;enterkeyhint&quot;&gt;enterkeyhint&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#enterkeyhint&quot; aria-labelledby=&quot;enterkeyhint&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Finally, we&amp;#39;re able to tweak the message that shows up in the mobile user&amp;#39;s virtual Enter key, thanks to the &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint&quot; rel=&quot;noopener noreferrer&quot;&gt;enterkeyhint&lt;/a&gt;&lt;/code&gt; attribute, which can be one of the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;done&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;enter&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;go&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;next&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;previous&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;search&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;send&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here are a few examples of that in action:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/1131f92c-57ce-4e15-8161-1be53f119cbb_Screen+Shot+2021-12-23+at+8.26.58+AM.png?auto=compress,format&quot; alt=&quot;Three screenshots from an iPhone with the virtual keyboard extended. The first shows an input focused that has the enterkeyhint of &amp;#39;done&amp;#39; which is shown on the keyboard, the next shows the hint and key of &amp;#39;enter&amp;#39;, and the last shows the hint and key of &amp;#39;next&amp;#39;.&quot; /&gt;&lt;/p&gt;&lt;p&gt;Why should we worry about tweaking a single key on our user&amp;#39;s virtual keyboard display? Submitting a form, especially a critical, sensitive form, can be nerve-wracking, and our users might be nervous about clicking the wrong button at the wrong time and submitting their form prematurely. By changing the &lt;code&gt;enterkeyhint&lt;/code&gt;, we can clue them in to what will happen when they click the button, so they know what&amp;#39;s safe or not.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;contact-form-demo&quot;&gt;Contact Form demo&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#contact-form-demo&quot; aria-labelledby=&quot;contact-form-demo&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The following demo comes from &lt;a href=&quot;https://htmlrecipes.dev/#contact-form&quot; rel=&quot;noopener noreferrer&quot;&gt;HtmlRecipes.dev&lt;/a&gt; with one tweak to not make the button submit the form strictly for demonstration so you can safely test the autocomplete values for the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    .demo {
  background-color: lightblue;
  display: grid;
  place-content: center;
}

.contact-form {
  /* demo reset from site styles */
  all: unset;
  max-width: 40ch;
  margin: auto;
  background-color: white;
  padding: 1rem 2rem;
  border-radius: 20px;
  box-shadow: 0 0 #0000, 0 0 #0000, 0 25px 50px -12px rgba(0, 0, 0, 0.65);
}

.contact-form label {
  display: block;
}

.contact-form input {
  width: 100%;
  height: 3em;
  margin-bottom: 1em;
}

.contact-form textarea {
  width: 100%;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Contact form using autocomplete&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.demo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.contact-form&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* demo reset from site styles */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 #0000&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0 0 #0000&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0 25px 50px -12px &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.65&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.contact-form label&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.contact-form input&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.contact-form textarea&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;form class=&quot;contact-form&quot;&gt;
  &lt;label for=&quot;full-name&quot;&gt;
    Full Name:
  &lt;/label&gt;
  &lt;input id=&quot;full-name&quot; name=&quot;full-name&quot; type=&quot;text&quot; autocomplete=&quot;name&quot; required=&quot;&quot; /&gt;
  &lt;label for=&quot;email-address&quot;&gt;
    Email Address:
  &lt;/label&gt;
  &lt;input id=&quot;email-address&quot; name=&quot;email-address&quot; type=&quot;email&quot; autocomplete=&quot;email&quot; required=&quot;&quot; /&gt;
  &lt;label for=&quot;message&quot;&gt;
    Message:
  &lt;/label&gt;
  &lt;textarea id=&quot;message&quot; name=&quot;message&quot; rows=&quot;5&quot; cols=&quot;30&quot; required=&quot;&quot;&gt;&lt;/textarea&gt;
  &lt;button type=&quot;button&quot;&gt;Submit&lt;/button&gt;
&lt;/form&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;bonus-tip-styling-form-fields&quot;&gt;Bonus tip: Styling form fields&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/#bonus-tip-styling-form-fields&quot; aria-labelledby=&quot;bonus-tip-styling-form-fields&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Steph has covered styling form fields over on her series on ModernCSS.dev:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/pure-css-custom-styled-radio-buttons/&quot; rel=&quot;noopener noreferrer&quot;&gt;Radio buttons&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/pure-css-custom-checkbox-style/&quot; rel=&quot;noopener noreferrer&quot;&gt;Checkboxes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/custom-select-styles-with-pure-css/&quot; rel=&quot;noopener noreferrer&quot;&gt;Selects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/custom-css-styles-for-form-inputs-and-textareas/&quot; rel=&quot;noopener noreferrer&quot;&gt;Text inputs and textareas&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  

  



&lt;footer&gt;
  &lt;h2&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/form-autocomplete/&quot;&gt;Ben Myers&lt;/a&gt;&lt;/h2&gt;
  &lt;img src=&quot;https://images.prismic.io/12daysofwebdev/58e2099e-a803-46c6-a14c-1a0c4bc3d646_benmyers.jpg?auto=compress,format&amp;rect=0,0,400,400&amp;w=150&amp;h=150&quot; alt=&quot;Ben Myers&quot; /&gt;
  &lt;p&gt;Hey, I&amp;#39;m Ben. I&amp;#39;m a React developer from McKinney, Texas. My teammates know me for my commitment to web accessibility, intentional inclusiveness, and unforgivable puns. I believe in writing the code you wish to see in the world—taking pride in the work you do and celebrating code for just how human it is. I&amp;#39;m passionate about learning and growing, and I&amp;#39;m just as passionate about sharing what I&amp;#39;ve learned with those around me. View more of my resources and link to my Twitch show at &lt;a href=&quot;https://benmyers.dev/&quot; rel=&quot;noopener noreferrer&quot;&gt;BenMyers.dev&lt;/a&gt;.&lt;/p&gt;
&lt;/footer&gt;

</content>
  </entry>
  <entry>
    <title>Web Speech API</title>
    <link href="https://12daysofweb.dev/2021/speech-api/"/>
    <updated>2021-12-22T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/speech-api/</id>
    <content type="html">



&lt;p&gt;Did you know your browser has speech recognition capabilities? (Well, &lt;a href=&quot;https://wiki.mozilla.org/Web_Speech_API_-_Speech_Recognition&quot; rel=&quot;noopener noreferrer&quot;&gt;except Firefox for now&lt;/a&gt;). &lt;/p&gt;&lt;p&gt;Similar to &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/&quot;&gt;the MediaStreams API we learned on Day 6&lt;/a&gt;, this API will trigger a prompt to get the user&amp;#39;s permission to listen to their microphone. Then we can set up logic to recognize words to send back a response within a chat-like interface.&lt;/p&gt;&lt;p&gt;To help us learn this API, we&amp;#39;ll be building a &amp;quot;Chat with Santa&amp;quot; application.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;intro-to-the-web-speech-api&quot;&gt;Intro to the Web Speech API&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#intro-to-the-web-speech-api&quot; aria-labelledby=&quot;intro-to-the-web-speech-api&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The API has two kinds of functionality - recognition and synthesis (aka text-to-speech, aka speaking text aloud). It&amp;#39;s important to know that current implementations in Chromium and Safari/webkit do not allow offline access so the service would not be available for progressive web apps (PWAs).&lt;/p&gt;&lt;p&gt;Additionally, the API is technically in experimental status, which you&amp;#39;ll see reflected in the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API#browser_compatibility&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN browser compatibility table&lt;/a&gt;. But we&amp;#39;re here to celebrate what the web is capable of, and this is certainly still an impressive bit of functionality!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;chat-with-santa-features&quot;&gt;&quot;Chat with Santa&quot; features&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#chat-with-santa-features&quot; aria-labelledby=&quot;chat-with-santa-features&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For our voice-enabled chat with Santa, we&amp;#39;ll need the following functionality:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Allow users to start and stop the speech recognition&lt;/li&gt;&lt;li&gt;Evaluate the speech transcript for keywords&lt;/li&gt;&lt;li&gt;Respond in the chat as Santa based on the keywords&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;chat-application-html-and-css&quot;&gt;Chat application HTML and CSS&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#chat-application-html-and-css&quot; aria-labelledby=&quot;chat-application-html-and-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As we&amp;#39;ve done throughout the series, we&amp;#39;ll start with the markup and styles.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Our application is for demonstration of the essential speech API recognition features and will not be fully accessible since we&amp;#39;ll not be building an alternative way to interact with the app beyond voice.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;First up, our HTML, which is quite simply a container, headline, button to start and stop the listening, and an unordered list to populate with the chat messages.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;santa-chat-app&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Chat with Santa&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;santa-listen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-state&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;inactive&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Start listening&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;santa-chat&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;#39;ll be using mostly flexbox to align our chat elements, and just a touch of flourish provided by a pseudo-element and&lt;code&gt; box-shadow&lt;/code&gt; to make the chat messages stand out.&lt;/p&gt;&lt;p&gt;There are two bits of state we&amp;#39;ll style for related to when the app is listening for speech. We&amp;#39;ll update the color of the button, and add a duo-tone green &lt;code&gt;box-shadow&lt;/code&gt; to the chat log as an extra visual cue that listening is active.&lt;/p&gt;&lt;p&gt;The style demo has added the &lt;code&gt;active&lt;/code&gt; class to preview that style.&lt;/p&gt;


  
    

    

    
    &lt;style&gt;
    .santa-chat-app {
  --santa-red-hue: 10;
  --santa-green-hue: 120;
  --santa-saturation: 90%;
  --santa-red: hsl(var(--santa-red-hue), var(--santa-saturation), 45%);
  --santa-green: hsl(var(--santa-green-hue), var(--santa-saturation), 35%);
  --sanata-green-light: hsl(var(--santa-green-hue), var(--santa-saturation), 85%);

  display: grid;
  gap: 2rem;
  justify-items: start;
  border: 2px solid var(--santa-red);
  border-radius: 0.5rem;
  padding: 2rem clamp(1.5rem, 5%, 2.5rem);
  font-family: system-ui, sans-serif;
}

.santa-chat-app h2 {
  margin: 0;
  color: var(--santa-red);
}

.santa-listen {
  all: unset;
  cursor: pointer;
  color: hsl(var(--santa-green-hue), var(--santa-saturation), 25%);
  border-radius: 0.5rem;
  border: 2px solid;
  padding: 0.25em 0.5em;
}

.santa-listen:is(:focus, :focus-visible) {
  outline: 2px dashed currentColor !important;
  outline-offset: 2px;
}

.santa-listen[data-state=listening] {
  color: var(--santa-red);
}

.santa-chat {
  list-style: none;
  margin: 0;
  padding: 1.25rem 1.5rem;
  justify-self: stretch;
  height: 20em;
  overflow-y: auto;
  border: 1px dashed grey;
  border-radius: 0.5rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.75rem;
  color: #222;
  font-size: 1.15rem;
}

.santa-chat.active {
  border-color: green;
  box-shadow: 0 0 0 4px var(--sanata-green-light), 0 0 0 6px var(--santa-green);
}

.message {
  position: relative;
  border-radius: 0.75rem;
  padding: 0.5rem 0.75rem;
}

.message::after {
  content: &quot;&quot;;
  position: absolute;
  top: 50%;
  right: 0;
  transform: translate(100%, -50%);
  border: 0.5em solid transparent;
}

.message--user {
  align-self: flex-end;
  background-color: var(--sanata-green-light);
  border: 1px solid var(--santa-green);
  box-shadow: 2px 2px 0 var(--santa-green);
}

.message--user::after {
  border-left-color: var(--santa-green);
}

.message--santa {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.25em;
  background-color: hsl(var(--santa-red-hue), var(--santa-saturation), 85%);
  border: 1px solid var(--santa-red);
  box-shadow: -2px 2px 0 var(--santa-red);
}

.message--santa::after {
  border-right-color: var(--santa-red);
  left: 0;
  transform: translate(-100%, -50%);
}

.message--santa::before {
  content: &quot;🎅&quot;;
  font-size: 1.15em;
  transform: translateY(-5%);
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Santa chat styles&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-chat-app&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--santa-red-hue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--santa-green-hue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 120&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--santa-saturation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 90%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--santa-red&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red-hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-saturation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 45%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--santa-green&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green-hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-saturation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 35%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--sanata-green-light&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green-hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-saturation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 85%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;justify-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.5rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-chat-app h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-listen&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green-hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-saturation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em 0.5em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-listen:is(:focus, :focus-visible)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px dashed currentColor &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-listen[data-state=listening]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-chat&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;justify-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; stretch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px dashed grey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-direction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; column&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex-end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.15rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.santa-chat.active&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 0 4px &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--sanata-green-light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0 0 0 6px &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem 0.75rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; -50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message--user&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex-end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--sanata-green-light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px 2px 0 &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message--user::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-left-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message--santa&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex-start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red-hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-saturation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 85%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -2px 2px 0 &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message--santa::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-right-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--santa-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; -50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.message--santa::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;🎅&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.15em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-5%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;santa-chat-app&quot;&gt;
  &lt;h2&gt;Chat with Santa&lt;/h2&gt;
  &lt;button class=&quot;santa-listen&quot; data-state=&quot;inactive&quot;&gt;Start listening&lt;/button&gt;
  &lt;ul class=&quot;santa-chat active&quot;&gt;
    &lt;li class=&quot;message message--user&quot;&gt;Hello, Santa!&lt;/li&gt;
    &lt;li class=&quot;message message--santa&quot;&gt;Ho ho ho - have you been good this year?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;adding-speech-recognition&quot;&gt;Adding Speech Recognition&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#adding-speech-recognition&quot; aria-labelledby=&quot;adding-speech-recognition&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To prepare our app for speech recognition, we&amp;#39;ll initiate a connection as recommended by the MDN docs, including setting our language.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Configure SpeechRecognition&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; SpeechRecognition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SpeechRecognition &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; webkitSpeechRecognition&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recognition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SpeechRecognition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lang &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;en-US&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we&amp;#39;ll access the two elements we&amp;#39;ll be manipulating - the listen button and the unordered list - as well as create our custom activate and deactivate functions.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Access chat elements&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listenButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.santa-listen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; speechLog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.santa-chat&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;activateChat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stop listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;deactivateChat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inactive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Start listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;start()&lt;/code&gt; and &lt;code&gt;stop()&lt;/code&gt; methods are part of the speech API. We&amp;#39;re also toggling the state of the listening button by altering our custom data-state attribute and the actual button text.&lt;/p&gt;&lt;p&gt;You may have noticed we remove the active class for deactivation but don&amp;#39;t set it as part of activation. That&amp;#39;s because there&amp;#39;s an API event we&amp;#39;ll use for attaching that state instead - &lt;code&gt;onstart&lt;/code&gt;. Functionally for our app, we could place it within &lt;code&gt;activateChat()&lt;/code&gt;, but it&amp;#39;s useful to know about the &lt;code&gt;onstart&lt;/code&gt; event.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onstart&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In addition to &lt;code&gt;onstart&lt;/code&gt;, we have two events that can signal that the API has stopped listening. The first is when the user actually stops talking which is &lt;code&gt;onspeechend&lt;/code&gt;. The other is triggered when the API hits a timeout which in Chrome for example seems to be 60 seconds. This timeout seems to be more of a &amp;quot;session&amp;quot; time before the API requires the user to re-initiate the action to start the recognition.&lt;/p&gt;&lt;p&gt;We&amp;#39;ll set both of these events to use &lt;code&gt;deactivateChat()&lt;/code&gt; so that the app doesn&amp;#39;t falsely appear to be listening.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onspeechend&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onend&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Speaking of the user initiating recognition - it&amp;#39;s time to finally hook up our listening button. We&amp;#39;ll use a simple click handler and check for the current &lt;code&gt;data-state&lt;/code&gt; to continue with either activating or deactivating recognition.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inactive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;activateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;providing-the-users-speech-result&quot;&gt;Providing the user&#39;s speech result&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#providing-the-users-speech-result&quot; aria-labelledby=&quot;providing-the-users-speech-result&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;At this stage, you could test our app and you would get the prompt for permission to access your microphone. But we need to connect the pieces to be able to output what you say and have Santa give a response.&lt;/p&gt;&lt;p&gt;This will be done via the &lt;code&gt;onresult&lt;/code&gt; event of the speech API. This is triggered when the recognition determines that a user has stopped speaking and has evaluated the speech. The important part here is the returned &lt;code&gt;transcript&lt;/code&gt; value.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onresult&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// get the results of the speech recognition&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transcript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once we have the &lt;code&gt;transcript&lt;/code&gt; value, we&amp;#39;ll output that back to the user so they can see what was &amp;quot;heard&amp;quot; by the recognition. We&amp;#39;ll do this by creating a new list element with the user classes and appending it to the list.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Create element for user message&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;newMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;message--user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newMessageTranscript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;newMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newMessageTranscript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Add transcript to DOM&lt;/span&gt;&lt;br /&gt;speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;responding-to-recognized-words-and-phrases&quot;&gt;Responding to recognized words and phrases&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#responding-to-recognized-words-and-phrases&quot; aria-labelledby=&quot;responding-to-recognized-words-and-phrases&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To create the illusion of Santa typing back, we&amp;#39;ll set a small timeout then pass the transcript off to a function we&amp;#39;ll create to handle the responses. This should be placed as the last thing in the &lt;code&gt;onresult&lt;/code&gt; event function.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;handleSantaResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;#39;ll kickstart the response function by adding a new list element populated with ellipses to allude to Santa &amp;quot;typing&amp;quot; a new message.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSantaResponse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;transcript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;message--santa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;typing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, to better be able to match against the transcript, we&amp;#39;ll transform it to lowercase, remove punctuation, and trim extra whitespace.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;transcript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transcript&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[&#92;.&#92;?,!]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;An upcoming feature of the speech API allows you to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/grammars&quot; rel=&quot;noopener noreferrer&quot;&gt;add your own grammar dictionary&lt;/a&gt; which will make word and phrase matching easier, but it is currently not supported in Safari.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;To prepare for responding, we&amp;#39;ll setup a default response if there are no matches. We&amp;#39;ll also have a default delay and a boolean to indicate if we should continue with listening or not. The delay will be modified to add a touch of &amp;quot;realness&amp;quot; of having Santa think about his response.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Happy Holidays!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; continueChat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we&amp;#39;ll have a series of simplistic searches for words and phrases to then alter the &lt;code&gt;santaResponse&lt;/code&gt;, etc. Here&amp;#39;s the initial one anticipating a greeting.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ho ho ho - have you been good this year?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the full demo you can see the other types of prepared responses. But I recommend keeping it hidden until you&amp;#39;ve tried out the chat first 😉&lt;/p&gt;&lt;p&gt;After our prepared responses, we update the &lt;code&gt;textContent&lt;/code&gt; of the list item we created and populated with ellipses earlier.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;setTimeout(() =&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    newResponse.textContent = santaResponse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;if (continueChat)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;activateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We also automatically begin speech recognition as long as &lt;code&gt;continueChat&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;. The one instance where &lt;code&gt;continueChat&lt;/code&gt; would not be true is when the user says &amp;quot;goodbye&amp;quot; or &amp;quot;bye&amp;quot;. However, the API may experience a session timeout before that point which would trigger the &lt;code&gt;onend&lt;/code&gt; event and the user would have to re-initiate the chat via the listen button.&lt;/p&gt;&lt;p&gt;That completes the setup for our Santa chat app! Try it out in the demo. &lt;/p&gt;&lt;p&gt;&lt;strong&gt;In my testing, you&amp;#39;ll get the best results in Chromium&lt;/strong&gt;. Safari seemed to take longer to respond and sometimes provided duplications in the transcript.&lt;/p&gt;
    

    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of Santa Chat speech recognition application&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Configure SpeechRecognition&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; SpeechRecognition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SpeechRecognition &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; webkitSpeechRecognition&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recognition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SpeechRecognition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lang &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;en-US&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Access chat elements&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listenButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#demo .santa-listen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; speechLog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#demo .santa-chat&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;activateChat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stop listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;deactivateChat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inactive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Start listening&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onstart&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onspeechend&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onend&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; listenButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inactive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;activateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onresult&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// get the results of the speech recognition&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transcript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Create element for user message&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;message--user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newMessageTranscript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newMessageTranscript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Add transcript to DOM&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;handleSantaResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSantaResponse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;transcript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;message--santa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  newResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;typing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  speechLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  transcript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transcript&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[&#92;.&#92;?,!]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Happy Holidays!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; continueChat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ho ho ho - have you been good this year?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    transcript &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;been good&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;yes i have&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;i guess so&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;maybe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Oh, jolly good! You&#39;ll have a full stocking!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    transcript &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;been bad&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;no i&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;naughty&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Oh dear! Rudolph will be sorry to hear that.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;thank you&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Of course! Anything else you want?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;how are you&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;you doing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;you busy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Feeling jolly! What do you want this year?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;i want&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;i&#39;d like&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;i would like&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;    transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;can i have&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;That&#39;s quite a list, the elves and I will do our best!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// includes does partial matching so this also works for &quot;goodbye&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bye&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    santaResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ho ho ho - See ya real soon! Don&#39;t forget my cookies!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    continueChat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    newResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; santaResponse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;continueChat&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;activateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;deactivateChat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;demo&quot; class=&quot;santa-chat-app&quot;&gt;
  &lt;h2&gt;Chat with Santa&lt;/h2&gt;
  &lt;button class=&quot;santa-listen&quot; data-state=&quot;inactive&quot;&gt;Start listening&lt;/button&gt;
  &lt;ul class=&quot;santa-chat&quot;&gt;&lt;/ul&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    // Configure SpeechRecognition
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.lang = &quot;en-US&quot;;

// Access chat elements
const listenButton = document.querySelector(&quot;#demo .santa-listen&quot;);
const speechLog = document.querySelector(&quot;#demo .santa-chat&quot;);

const activateChat = () =&gt; {
  recognition.start();
  listenButton.dataset.state = &quot;listening&quot;;
  listenButton.textContent = &quot;Stop listening&quot;;
};

const deactivateChat = () =&gt; {
  recognition.stop();
  speechLog.classList.remove(&quot;active&quot;);
  listenButton.dataset.state = &quot;inactive&quot;;
  listenButton.textContent = &quot;Start listening&quot;;
};

recognition.onstart = () =&gt; {
  speechLog.classList.add(&quot;active&quot;);
};

recognition.onspeechend = () =&gt; {
  deactivateChat();
};

recognition.onend = () =&gt; {
  deactivateChat();
};

listenButton.addEventListener(&quot;click&quot;, () =&gt; {
  const state = listenButton.dataset.state;

  if (state === &quot;inactive&quot;) {
    activateChat();
  } else {
    deactivateChat();
  }
});

recognition.onresult = function (event) {
  // get the results of the speech recognition
  const transcript = event.results[0][0].transcript;

  // Create element for user message
  const newMessage = document.createElement(&quot;li&quot;);
  newMessage.classList.add(&quot;message&quot;, &quot;message--user&quot;);
  const newMessageTranscript = document.createTextNode(transcript);
  newMessage.appendChild(newMessageTranscript);

  // Add transcript to DOM
  speechLog.append(newMessage);

  setTimeout(() =&gt; {
    handleSantaResponse(transcript);
  }, 500);
};

const handleSantaResponse = (transcript) =&gt; {
  const newResponse = document.createElement(&quot;li&quot;);
  newResponse.classList.add(&quot;message&quot;, &quot;message--santa&quot;);
  const typing = document.createTextNode(&quot;...&quot;);
  newResponse.appendChild(typing);
  speechLog.append(newResponse);

  transcript = transcript
    .toLowerCase()
    .replace(/[&#92;.&#92;?,!]/gm, &quot;&quot;)
    .trim();

  let santaResponse = &quot;Happy Holidays!&quot;;
  let delay = 800;
  let continueChat = true;

  if (transcript.includes(&quot;hello&quot;) || transcript.includes(&quot;hi&quot;)) {
    santaResponse = &quot;Ho ho ho - have you been good this year?&quot;;
    delay = 1200;
  }

  if (
    transcript === &quot;yes&quot; ||
    transcript.includes(&quot;been good&quot;) ||
    transcript.includes(&quot;yes i have&quot;) ||
    transcript.includes(&quot;i guess so&quot;) ||
    transcript.includes(&quot;maybe&quot;)
  ) {
    santaResponse = &quot;Oh, jolly good! You&#39;ll have a full stocking!&quot;;
    delay = 1000;
  }

  if (
    transcript === &quot;no&quot; ||
    transcript.includes(&quot;been bad&quot;) ||
    transcript.includes(&quot;no i&quot;) ||
    transcript.includes(&quot;naughty&quot;)
  ) {
    santaResponse = &quot;Oh dear! Rudolph will be sorry to hear that.&quot;;
    delay = 1000;
  }

  if (transcript.includes(&quot;thank you&quot;)) {
    santaResponse = &quot;Of course! Anything else you want?&quot;;
  }

  if (
    transcript.includes(&quot;how are you&quot;) ||
    transcript.includes(&quot;you doing&quot;) ||
    transcript.includes(&quot;you busy&quot;)) {
      santaResponse = &quot;Feeling jolly! What do you want this year?&quot;;
      delay = 1200;
  }

  if (
    transcript.includes(&quot;i want&quot;) ||
    transcript.includes(&quot;i&#39;d like&quot;) ||
    transcript.includes(&quot;i would like&quot;) ||
    transcript.includes(&quot;can i have&quot;)
  ) {
    santaResponse = &quot;That&#39;s quite a list, the elves and I will do our best!&quot;;
    delay = 1200;
  }

  // includes does partial matching so this also works for &quot;goodbye&quot;
  if (transcript.includes(&quot;bye&quot;)) {
    santaResponse = &quot;Ho ho ho - See ya real soon! Don&#39;t forget my cookies!&quot;;
    continueChat = false;
  }

  setTimeout(() =&gt; {
    newResponse.textContent = santaResponse;

    if (continueChat) {
      activateChat();
    } else {
      deactivateChat();
    }
  }, delay);
};

    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-for-the-web-speech-api&quot;&gt;Additional resources for the Web Speech API&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/speech-api/#additional-resources-for-the-web-speech-api&quot; aria-labelledby=&quot;additional-resources-for-the-web-speech-api&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Given the experimental status and inability to work offline, the speech API isn&amp;#39;t really ready to perform critical functions. But it can be fun for personal projects or for a limited well-known audience.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Review &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API&quot; rel=&quot;noopener noreferrer&quot;&gt;all of the web speech API capabilities&lt;/a&gt; on MDN&lt;/li&gt;&lt;li&gt;Alvaro Montoro created &lt;a href=&quot;https://dev.to/alvaromontoro/using-js-speech-recognition-to-build-a-virtual-assistant-1957&quot; rel=&quot;noopener noreferrer&quot;&gt;a virtual assistant&lt;/a&gt; for his wife to use to help teach Spanish which includes the speech synthesis functionality to actually vocalize the responses.&lt;/li&gt;&lt;li&gt;Louis Hoebregts worked with Alex Trost to build &lt;a href=&quot;https://frontend.horse/episode/voice-powered-image-search&quot; rel=&quot;noopener noreferrer&quot;&gt;a voice-powered image search&lt;/a&gt; that connects to the Unsplash API&lt;/li&gt;&lt;li&gt;On day 20 of Wes Bos&amp;#39; free JavaScript 30 course, you&amp;#39;ll learn &lt;a href=&quot;https://javascript30.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;how to receive continuous speech results&lt;/a&gt; for building out things like a to-do list&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>CSS Animation</title>
    <link href="https://12daysofweb.dev/2021/css-animation/"/>
    <updated>2021-12-21T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/css-animation/</id>
    <content type="html">



&lt;p&gt;Let&amp;#39;s get right to it! We&amp;#39;ll review:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#transitions-and-transforms&quot;&gt;transitions and transforms&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#keyframe-animations&quot;&gt;keyframe animations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#motion-animation-with-offset-path&quot;&gt;motion animation with offset-path&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#scroll-linked-animations&quot;&gt;scroll-linked animations&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Revisit Day 7 to &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/&quot;&gt;review the &lt;code&gt;prefers-reduced-motion&lt;/code&gt; preference query&lt;/a&gt; as well as other considerations before you start adding animation.&lt;/p&gt;&lt;/aside&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;transitions-and-transforms&quot;&gt;Transitions and Transforms&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#transitions-and-transforms&quot; aria-labelledby=&quot;transitions-and-transforms&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Animating by transitioning transforms is the most performant way to apply subtle movement. It&amp;#39;s often used to transition between states such as for an interactive element&amp;#39;s hover or focus state. Transforms can also be used to provide &amp;quot;entrance&amp;quot; and &amp;quot;exit&amp;quot; animations.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s a selection of 4 transition utility classes using transforms that come from one of my other projects, &lt;a href=&quot;https://smolcss.dev/#smol-transitions&quot; rel=&quot;noopener noreferrer&quot;&gt;SmolCSS&lt;/a&gt;. We&amp;#39;re triggering the transition of the child elements on &lt;code&gt;:hover&lt;/code&gt; of the parent. The reason for this is that for transitions that move the element, it could end up moving out from under the mouse and causing a flicker between states. The rise transition is particularly in danger of that behavior.&lt;/p&gt;&lt;p&gt;We&amp;#39;re also wrapping our effect class in a media query check for &lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt; that instantly jumps the transition to the final state. You can learn more about why this is important on &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/&quot;&gt;Day 7 about preference queries&lt;/a&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    .smol-transitions {
  display: grid;
  place-content: center;
}

.smol-transitions &gt; * {
  --transition-property: transform;
  --transition-duration: 180ms;

  transition: var(--transition-property) var(--transition-duration) ease-in-out;
  background-color: lightblue;
  padding: 0.25em;
  font-size: 1.35rem;
  border-radius: 0.25rem;
}

.rise:hover &gt; * {
  transform: translateY(-25%);
}

.rotate:hover &gt; * {
  transform: rotate(15deg);
}

.zoom:hover &gt; * {
  transform: scale(1.3);
}

.fade &gt; * {
  --transition-property: opacity;
  --transition-duration: 500ms;
}

.fade:hover &gt; * {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .smol-transitions &gt; * {
    --transition-duration: 0.01ms;
  }
}

/* demo dispay */
.smol-flexbox-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.smol-flexbox-grid &gt; * {
  flex: 1 1 20ch;
  margin: 0;
}

.smol-transitions {
  padding: 1rem;
  border: 2px dashed;
  border-radius: 0.5rem;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Transition utility classes&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.smol-transitions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.smol-transitions &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--transition-property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--transition-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 180ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--transition-property&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--transition-duration&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ease-in-out&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.35rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.rise:hover &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-25%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.rotate:hover &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;15deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.zoom:hover &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.fade &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--transition-property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; opacity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--transition-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 500ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.fade:hover &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; reduce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.smol-transitions &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--transition-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.01ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* demo dispay */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.smol-flexbox-grid&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.smol-flexbox-grid &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1 1 20ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.smol-transitions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px dashed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;ul class=&quot;smol-flexbox-grid&quot;&gt;
  &lt;li class=&quot;smol-transitions rise&quot;&gt;&lt;span&gt;rise&lt;/span&gt;&lt;/li&gt;
  &lt;li class=&quot;smol-transitions rotate&quot;&gt;&lt;span&gt;rotate&lt;/span&gt;&lt;/li&gt;
  &lt;li class=&quot;smol-transitions zoom&quot;&gt;&lt;span&gt;zoom&lt;/span&gt;&lt;/li&gt;
  &lt;li class=&quot;smol-transitions fade&quot;&gt;&lt;span&gt;fade&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;keyframe-animations&quot;&gt;Keyframe Animations&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#keyframe-animations&quot; aria-labelledby=&quot;keyframe-animations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The next step up from transitions and transforms is keyframe animations&lt;/p&gt;&lt;p&gt;Keyframes are defined as different steps from 0 to 100% which correspond to that point along the duration of the animation. For example for a &lt;code&gt;400ms&lt;/code&gt; animation, &lt;code&gt;25%&lt;/code&gt; would correspond with the &lt;code&gt;100ms&lt;/code&gt; point.&lt;/p&gt;&lt;p&gt;Typically an animation moves smoothly (aka &amp;quot;tweens&amp;quot;) between the keyframes, but you can also use the &lt;code&gt;step()&lt;/code&gt; timing function to move sharply between them. This is desirable for something like sprite animation for characters to create a walking sequence.&lt;/p&gt;&lt;p&gt;This demo shows an example of a default tweened animation and a stepped animation. We&amp;#39;re using the &lt;code&gt;animation&lt;/code&gt; shorthand, and you can &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot; rel=&quot;noopener noreferrer&quot;&gt;review all the &lt;code&gt;animation&lt;/code&gt; options on MDN&lt;/a&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    .keyframe-animations {
  display: grid;
  gap: 1rem;
}

.animated {
  position: relative;
  left: 0;
  width: 12ch;
  padding: 0.15em;
  text-align: center;
  background-color: lightblue;
  animation: glide 5000ms var(--timing-function, linear) infinite;
  animation-play-state: var(--play-state, paused);
}

.stepped {
  --timing-function: steps(4);

  background-color: goldenrod;
}

@keyframes glide {
  50% {
    background-color: palevioletred;
  }
  100% {
    left: calc(100% - 12ch);
    background-color: unset;
  } 
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of tweened vs. stepped animation timing&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.keyframe-animations&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.animated&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 12ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.15em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; glide 5000ms &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--timing-function&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; linear&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; infinite&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-play-state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--play-state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paused&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.stepped&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--timing-function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; goldenrod&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; glide&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;50%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; palevioletred&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% - 12ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; animation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;animate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;animation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playpause &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isPlaying &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; playpause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;playing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; animate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;animation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isPlaying&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      animate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--play-state&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      playpause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      playpause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play animation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      animate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--play-state&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;running&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      playpause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;playing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      playpause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pause animation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;button class=&quot;play-pause&quot; type=&quot;button&quot; data-state=&quot;paused&quot; data-animate=&quot;.keyframe-animations&quot;&gt;Play animation&lt;/button&gt;
&lt;div class=&quot;keyframe-animations&quot;&gt;
  &lt;div class=&quot;animated&quot;&gt;I&#39;m tweened&lt;/div&gt;
  &lt;div class=&quot;animated stepped&quot;&gt;I&#39;m stepped&lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    document.addEventListener(&quot;click&quot;, (e) =&gt; {
  const animation = e.target.dataset.animate;

  if (animation) {
    const playpause = e.target;
    const isPlaying = playpause.dataset.state === &quot;playing&quot;;
    const animate = document.querySelector(animation);

    if (isPlaying) {
      animate.style.setProperty(&#39;--play-state&#39;, &#39;paused&#39;);
      playpause.dataset.state = &#39;paused&#39;;
      playpause.textContent = &quot;Play animation&quot;;
    } else {
      animate.style.setProperty(&#39;--play-state&#39;, &#39;running&#39;);
      playpause.dataset.state = &#39;playing&#39;;
      playpause.textContent = &quot;Pause animation&quot;;
    }
  }
});
    &lt;/script&gt;
    

    

    
    &lt;p&gt;Learn more about &lt;a href=&quot;https://www.youtube.com/watch?v=_Vrbb5BvD2Q&quot; rel=&quot;noopener noreferrer&quot;&gt;how to think about and create keyframe animations&lt;/a&gt; from Amit Sheen at LondonCSS.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;motion-animation-with-offset-path&quot;&gt;Motion animation with offset-path&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#motion-animation-with-offset-path&quot; aria-labelledby=&quot;motion-animation-with-offset-path&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Motion_Path&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS motion path&lt;/a&gt; allows moving an object along a path which is drawing using SVG path syntax. Previously called &lt;code&gt;motion-path&lt;/code&gt;, the current critical property is now &lt;code&gt;offset-path&lt;/code&gt;. It is at least partially supported in Chromium and Firefox with Safari support on the way (currently in the technical preview).&lt;/p&gt;&lt;p&gt;While there are times this can remove the need for a heavier JS library solution, the biggest drawback is lack of built-in native support for scaling the path or making it relative to a container. Depending on your viewport width, you may or may not see the entire timeline of the demo. Michelle Barker has &lt;a href=&quot;https://css-irl.info/responsive-css-motion-path/&quot; rel=&quot;noopener noreferrer&quot;&gt;a resizing solution via scaling&lt;/a&gt;, and Jhey provides a tutorial as well as library to accomplish &lt;a href=&quot;https://css-tricks.com/create-a-responsive-css-motion-path-sure-we-can/&quot; rel=&quot;noopener noreferrer&quot;&gt;responsive resizing of the path&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Additionally, SVG path syntax can be tricky, especially if you do not have a vector drawing program. An online tool I found useful in creating the demo was &lt;a href=&quot;https://yqnn.github.io/svg-path-editor/&quot; rel=&quot;noopener noreferrer&quot;&gt;SvgPathEditor&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In the following demo, if you are on iOS or Safari 15.2 or less, you will see the fallback to using CSS transitions and transforms.&lt;/p&gt;&lt;p&gt;Michelle has also written a much more &lt;a href=&quot;https://css-irl.info/fun-with-css-motion-path/&quot; rel=&quot;noopener noreferrer&quot;&gt;comprehensive overview of CSS Motion Path&lt;/a&gt; with several great demos.&lt;/p&gt;
    

    
    &lt;style&gt;
    .sleigh-ride {
  height: 180px;
  overflow: hidden;
  background-color: lightblue;
}

.sleigh-ride img {
  offset-path: path(&#39;M -1 120 s 165 -5 346 -32 s 179 9 411 25&#39;);
  animation: ride 6000ms ease-in-out var(--play-state, paused);
  transform-origin: left center;
  opacity: 0;
}

@supports not (offset-path: path(&#39;M 1 1&#39;)) {
  .sleigh-ride img {
    --sleigh-position: 100%;
    --sleigh-transform: translateY(25%) rotate(12deg);

    position: relative;
    left: 0;
    transform: translateY(150%) rotate(-12deg);
  }
}

@keyframes ride {
  5%, 95% {
    opacity: 1;
  }
  100% {
    offset-distance: 100%;
    left: var(--sleigh-position, 0);
    transform: var(--sleigh-transform, none);
    opacity: 0;
  }
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of offset-path animating Santa&#39;s sleigh&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.sleigh-ride&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 180px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.sleigh-ride img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;offset-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;M -1 120 s 165 -5 346 -32 s 179 9 411 25&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ride 6000ms ease-in-out &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--play-state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paused&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform-origin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; left center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;offset-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;M 1 1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.sleigh-ride img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--sleigh-position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--sleigh-transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;25%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;12deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;150%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-12deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; ride&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;5%, 95%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;offset-distance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--sleigh-position&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--sleigh-transform&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.sleigh-ride img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;animationend&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sleigh &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sleighPlayPause &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;animate-sleigh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// disable animation to reset for replay&lt;/span&gt;&lt;br /&gt;    sleigh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;animation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// reset play state and button state&lt;/span&gt;&lt;br /&gt;    document&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.sleigh-ride&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--play-state&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;paused&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    sleighPlayPause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;paused&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    sleighPlayPause&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play animation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// trigger reflow to successfully replay animation&lt;/span&gt;&lt;br /&gt;    sleigh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// re-enable animation&lt;/span&gt;&lt;br /&gt;    sleigh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;button id=&quot;animate-sleigh&quot; class=&quot;play-pause&quot; type=&quot;button&quot; data-state=&quot;paused&quot; data-animate=&quot;.sleigh-ride&quot;&gt;Play animation&lt;/button&gt;
&lt;div class=&quot;sleigh-ride&quot;&gt;
  &lt;img src=&quot;https://12daysofweb.dev/img/santa-sleigh.svg&quot; alt=&quot;silhouette of Santa on his sleigh with the reindeer in flight&quot; /&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    document
  .querySelector(&quot;.sleigh-ride img&quot;)
  .addEventListener(&quot;animationend&quot;, (e) =&gt; {
    const sleigh = e.target;
    const sleighPlayPause = document.getElementById(&quot;animate-sleigh&quot;);

    // disable animation to reset for replay
    sleigh.style.animation = &quot;none&quot;;

    // reset play state and button state
    document
      .querySelector(&quot;.sleigh-ride&quot;)
      .style.setProperty(&quot;--play-state&quot;, &quot;paused&quot;);
    sleighPlayPause.dataset.state = &quot;paused&quot;;
    sleighPlayPause.textContent = &quot;Play animation&quot;;

    // trigger reflow to successfully replay animation
    sleigh.offsetWidth;
    // re-enable animation
    sleigh.removeAttribute(&quot;style&quot;);
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;scroll-linked-animations&quot;&gt;Scroll-Linked Animations&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#scroll-linked-animations&quot; aria-labelledby=&quot;scroll-linked-animations&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;On the cutting-edge of native CSS animation capabilities are &lt;a href=&quot;https://drafts.csswg.org/scroll-animations-1/&quot; rel=&quot;noopener noreferrer&quot;&gt;scroll-linked animations&lt;/a&gt;. These animations enhance keyframe animations by attaching them to scroll position instead of the classic timeline.&lt;/p&gt;&lt;p&gt;Unfortunately, these are not stable in any browser but are available as an experiment in Chromium 89+ if you enable &amp;quot;Experimental Web Platform Features&amp;quot; under &lt;code&gt;chrome://flags&lt;/code&gt;. I recommend doing this in Chrome Canary to prevent accidentally harming your normal browsing experience if you forget you have this on.&lt;/p&gt;&lt;p&gt;For more demos and a very thorough explanation of how scroll-linked animations work and what they&amp;#39;re capable of, be sure to watch &lt;a href=&quot;https://www.youtube.com/watch?v=NS4lmu6AJuI&quot; rel=&quot;noopener noreferrer&quot;&gt;Bramus Van Damme presentation from CSS Cafe&lt;/a&gt;. Once you have the experimental flag on, you can also peruse his &lt;a href=&quot;https://codepen.io/collection/DkdaQK&quot; rel=&quot;noopener noreferrer&quot;&gt;collection of demos on CodePen&lt;/a&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    @keyframes progressbar {
  0% {
    transform: scaleX(0);
  }
  100% {
    transform: scaleX(1);
  }
}

@scroll-timeline progressbar-timeline {
  time-range: var(--progress-time);
  source: selector(#scroll-animation);
}

.progress-bar {
  background-color: blue;
  height: 1rem;
  position: sticky;
  top: 0;
  transform-origin: left;
  animation: progressbar linear forwards var(--progress-time, 0);
  animation-timeline: progressbar-timeline;
}

#scroll-animation {
  position: relative;
  height: max(10rem, 30vh);
  overflow-y: auto;
}

.warning {
  background-color: lightyellow;
  border: 2px solid orange;
  padding: 1rem;
}

@supports (animation-timeline: yes) {
  .warning {
    display: none;
  }

  .progress-bar {
    --progress-time: 1s;
  }
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of a scroll-linked progress indicator&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; progressbar&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;0%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scaleX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scaleX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@scroll-timeline&lt;/span&gt; progressbar-timeline&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;time-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--progress-time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;#scroll-animation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.progress-bar&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; sticky&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform-origin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; left&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; progressbar linear forwards &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--progress-time&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; progressbar-timeline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#scroll-animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;10rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 30vh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.warning&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightyellow&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid orange&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.warning&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.progress-bar&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--progress-time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;scroll-animation&quot;&gt;

  &lt;div class=&quot;progress-bar&quot;&gt;&lt;/div&gt;

  &lt;p class=&quot;warning&quot;&gt;⚠️ Your browser does not support CSS Scroll-Linked Animations. View this demo by using Chromium 89+ with “Experimental Web Platform Features” enabled.&lt;/p&gt;

  &lt;p&gt;Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maxime nemo accusamus velit sunt atque maiores neque!&lt;/p&gt;
  &lt;p&gt;Dicta sint, quo nesciunt expedita quisquam id ipsum quaerat minima voluptate aut in, numquam unde? Expedita.&lt;/p&gt;
  &lt;p&gt;Nihil itaque esse, molestiae soluta minus earum temporibus dignissimos hic. Ab provident quasi voluptatem distinctio odit!&lt;/p&gt;
  &lt;p&gt;Labore ipsa architecto provident ullam, molestias assumenda obcaecati! Libero quidem doloremque voluptatum repellendus cumque facere sit!&lt;/p&gt;
  &lt;p&gt;Quas animi recusandae corrupti repellat culpa dolore, temporibus repudiandae omnis eum atque distinctio tempora ullam consequatur.&lt;/p&gt;
  &lt;p&gt;Ipsam molestiae deleniti cumque, maxime, error nulla sunt veniam corporis qui laboriosam quas excepturi voluptatibus laborum!&lt;/p&gt;
  &lt;p&gt;Unde iste repellat accusamus, quibusdam corporis placeat velit, cumque dolorum labore voluptas eligendi porro saepe rerum.&lt;/p&gt;
  &lt;p&gt;Laboriosam in error ipsam, dolorem aliquam magnam officiis totam exercitationem doloribus dicta excepturi incidunt unde earum!&lt;/p&gt;
  &lt;p&gt;Quas animi recusandae corrupti repellat culpa dolore, temporibus repudiandae omnis eum atque distinctio tempora ullam consequatur.&lt;/p&gt;
  &lt;p&gt;Ipsam molestiae deleniti cumque, maxime, error nulla sunt veniam corporis qui laboriosam quas excepturi voluptatibus laborum!&lt;/p&gt;
  &lt;p&gt;Unde iste repellat accusamus, quibusdam corporis placeat velit, cumque dolorum labore voluptas eligendi porro saepe rerum.&lt;/p&gt;
  &lt;p&gt;Laboriosam in error ipsam, dolorem aliquam magnam officiis totam exercitationem doloribus dicta excepturi incidunt unde earum!&lt;/p&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;bonus-3d-css-animation&quot;&gt;Bonus: 3D CSS animation&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-animation/#bonus-3d-css-animation&quot; aria-labelledby=&quot;bonus-3d-css-animation&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Transforms also provide the opportunity to create 3D animation.&lt;/p&gt;&lt;p&gt;Get inspired by &lt;a href=&quot;https://codepen.io/amit_sheen&quot; rel=&quot;noopener noreferrer&quot;&gt;these jaw-dropping 3D animations&lt;/a&gt; created by Amit Sheen. Then check out Amit walking through &lt;a href=&quot;https://www.youtube.com/watch?v=NdftnCDwKaU&quot; rel=&quot;noopener noreferrer&quot;&gt;how to create 3D shapes&lt;/a&gt; with Kevin Powell and begin animating them. &lt;/p&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Image Display Elements</title>
    <link href="https://12daysofweb.dev/2021/image-display-elements/"/>
    <updated>2021-12-20T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/image-display-elements/</id>
    <content type="html">



&lt;p&gt;&lt;a href=&quot;https://css-tricks.com/images-are-hard/&quot; rel=&quot;noopener noreferrer&quot;&gt;Images on the web are hard&lt;/a&gt;. In this article, we&amp;#39;re going to focus on the options for the display of responsive images.&lt;/p&gt;&lt;p&gt;There are a few different ways to add images to your page depending on what you care about in regards to what part of the image is displayed, the quality, and the performance. This is a high-touch overview that really only scratches the surface of these methods. Be sure to &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#additional-resources-on-image-display-and-performance&quot;&gt;check the additional resources&lt;/a&gt; for more assistance researching the best method for your use case.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;basic-img-element&quot;&gt;Basic img element&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#basic-img-element&quot; aria-labelledby=&quot;basic-img-element&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you have optimized your image and aren&amp;#39;t doing anything unusual with its display and aren&amp;#39;t concerned about serving higher density images for retina screens, just a simple &lt;code&gt;img&lt;/code&gt; will do.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;#39;ve intentionally added the width and height attributes here to give the browser information about the image&amp;#39;s intrinsic aspect ratio. Evergreen browsers now will pick up on the computed aspect ratio and prop open the space necessary for the image while waiting for it to download which can reduce cumulative layout shift. &lt;a href=&quot;https://www.youtube.com/watch?v=4-d_SoCHeWE&quot; rel=&quot;noopener noreferrer&quot;&gt;Watch Jen Simmons explain more about how it works&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;img-with-srcset&quot;&gt;img with srcset&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#img-with-srcset&quot; aria-labelledby=&quot;img-with-srcset&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you want to begin to have some performance gains, you can save out your image in multiple sizes. Then, define them within the &lt;code&gt;srcset&lt;/code&gt; attribute on a single &lt;code&gt;img&lt;/code&gt; along with the value of their intrinsic (actual) width or the pixel density you prefer to be used. The browser will select the optimum choice given conditions like the viewport size, resolution, user preferences, and bandwidth.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-small.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-large.jpg 1600w,&lt;br /&gt;        image-medium.jpg 768w,&lt;br /&gt;        image-small.jpg 320w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;800&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-1x.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-3x.jpg 3x,&lt;br /&gt;        image-2x.jpg 2x,&lt;br /&gt;        image-1x.jpg 1x&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;800&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;#39;re still including &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; to give the browser the aspect ratio hint. It&amp;#39;s ok that the browser might choose a different image size because the assumption is a single image is resized which means the aspect ratio is the same throughout, regardless of ultimate rendered size.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;img-with-srcset-and-sizes&quot;&gt;img with srcset and sizes&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#img-with-srcset-and-sizes&quot; aria-labelledby=&quot;img-with-srcset-and-sizes&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With only &lt;code&gt;srcset&lt;/code&gt; to go off of, the browser still has to wait for CSS to help determine the size to render. You can provide an additional hint by also adding the &lt;code&gt;sizes&lt;/code&gt; attribute which relates to approximately how large the image will render within your layout.&lt;/p&gt;&lt;p&gt;The sizes attribute will be ignored if &lt;code&gt;srcset&lt;/code&gt; is not provided. This is because the matching size will inform which image within &lt;code&gt;srcset&lt;/code&gt; to use. The other condition is that &lt;code&gt;srcset&lt;/code&gt; must be using widths and not density for this relationship to work.&lt;/p&gt;&lt;p&gt;When using &lt;code&gt;sizes&lt;/code&gt;, the format is &lt;code&gt;[media condition] [display width], [media condition] [display width], [display width]&lt;/code&gt; where &lt;code&gt;display width&lt;/code&gt; is the intended width in your layout. The last value in the list must not have the media condition. &lt;/p&gt;&lt;p&gt;The browser will use the first matching media condition in the list based on device size and then select the exact &lt;code&gt;srcset&lt;/code&gt; size if there&amp;#39;s a match or the next largest size if there&amp;#39;s no exact match.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-small.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-large.jpg 1600w,&lt;br /&gt;        image-medium.jpg 768w,&lt;br /&gt;        image-small.jpg 320w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 120ch) 33vw, 100vw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;800&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In that example, I&amp;#39;m letting the browser know that on a larger viewport I expect my image to take up roughly a third of the available space because it will be in a 3-column grid. Below that point, I expect it to take up essentially full width so we don&amp;#39;t have to be more specific than &lt;code&gt;100vw&lt;/code&gt;. This still leaves it up to the browser to choose exactly which image to serve to best fit the layout expectations I have provided as well as its other conditions mentioned previously.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;art-directing-with-picture&quot;&gt;Art directing with picture&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#art-directing-with-picture&quot; aria-labelledby=&quot;art-directing-with-picture&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you would like more control over which image is used and the flexibility for varying aspect ratios (aka &amp;quot;&lt;a href=&quot;http://usecases.responsiveimages.org/#art-direction&quot; rel=&quot;noopener noreferrer&quot;&gt;art directing&lt;/a&gt;&amp;quot; the image selected), then look to the &lt;code&gt;picture&lt;/code&gt; element.&lt;/p&gt;&lt;p&gt;This involves a series of source elements that use the media attribute to define the media condition at which an image should be displayed. It&amp;#39;s essentially like defining media query breakpoints directly on the image with the advantage of the browser knowing exactly which image to choose and start downloading even when CSS isn&amp;#39;t available yet.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 600px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-landscape.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-portrait.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image-landscape.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This method removes browser heuristics beyond viewport size from the equation and puts the responsibility back on you to provide the best image for the user. If your image maintains a consistent aspect ratio across various sizes, choose the &lt;code&gt;img&lt;/code&gt; with &lt;code&gt;srcset&lt;/code&gt; option or keep reading for a combination option.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s a video showing the art direction idea in action. Above &lt;code&gt;480px&lt;/code&gt; viewports, a landscape image is shown where a woman is laughing while sitting in a meeting at a Mac laptop with another woman who is partially visible turned to her with a hand raised mid-storytelling. Below that viewport size, the image is cropped in to feature the laughing woman.&lt;/p&gt;&lt;video class=&quot;video-player&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://12daysofweb.dev/img/art-direction-picture.mp4&quot;&gt;&lt;/video&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;offering-modern-image-formats&quot;&gt;Offering modern image formats&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#offering-modern-image-formats&quot; aria-labelledby=&quot;offering-modern-image-formats&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If your primary goal is to score some performance wins, then the &lt;code&gt;picture&lt;/code&gt; element is again what you need. It allows you to list images using modern image formats like &lt;code&gt;WebP&lt;/code&gt;, &lt;code&gt;AVIF&lt;/code&gt;, and &lt;code&gt;JPEG XL&lt;/code&gt; for the browser to select from, where the first supported type by DOM order of your &lt;code&gt;source&lt;/code&gt; elements will be used.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.jxl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/jxl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.avif&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/avif&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/jpeg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;#39;re once again providing width and height attributes for this method to ask the browser to hold open space for the image to load into.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;prioritizing-performance&quot;&gt;Prioritizing performance&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#prioritizing-performance&quot; aria-labelledby=&quot;prioritizing-performance&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To get the best of modern image formats while also allowing the browser to determine which image is best for the user&amp;#39;s current context, we can use the &lt;code&gt;srcset&lt;/code&gt; attribute on sources within &lt;code&gt;picture&lt;/code&gt;. Users of browsers with support for &lt;code&gt;WebP&lt;/code&gt; or other modern formats will enjoy a significant performance boost compared to only providing standard &lt;code&gt;jpeg&lt;/code&gt; images within a single &lt;code&gt;img&lt;/code&gt; &lt;code&gt;srcset&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_200.webp 200w, &lt;br /&gt;      wreath-w_660.webp 660w, &lt;br /&gt;      wreath-w_960.webp 960w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/jpeg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_200.jpg 200w,&lt;br /&gt;      wreath-w_660.jpg 660w,&lt;br /&gt;      wreath-w_960.jpg 960w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_660.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;960&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;640&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the demo, resize your viewport and then hover over the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag in dev tools to see which image type and size was selected by the browser. Since we haven&amp;#39;t used the &lt;code&gt;media&lt;/code&gt; attribute, if your browser has downloaded a larger size it may not switch to the smaller size for a resize event since there is no performance gain. A refresh may trigger a change in the size selected for smaller viewports.&lt;/p&gt;&lt;p&gt;Also, note that the chosen size depends on not just viewport CSS pixels but also pixel density which may cause a larger than expected image to be selected. As in, the &lt;code&gt;660w&lt;/code&gt; image doesn&amp;#39;t mean that image will be selected at &lt;code&gt;660px&lt;/code&gt; viewports.&lt;/p&gt;
    

    
    &lt;style&gt;
    /* ensure the image resizes with its container
as well as keeping its aspect ratio */
img {
  max-width: 100%;
  height: auto;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of srcset on source in picture&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* ensure the image resizes with its container&lt;br /&gt;as well as keeping its aspect ratio */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p&gt;Lorem ipsum dolor sit, amet consectetur adipisicing elit. Suscipit, reprehenderit doloremque. Tempore, esse dolorum? Quasi sunt sed temporibus perferendis, officia voluptatum sit fuga doloremque repellat, deleniti quod officiis esse mollitia.&lt;/p&gt;

&lt;picture&gt;
  &lt;source type=&quot;image/webp&quot; srcset=&quot;https://12daysofweb.dev/img/wreath-w_200.webp 200w, https://12daysofweb.dev/img/wreath-w_660.webp 660w, https://12daysofweb.dev/img/wreath-w_960.webp 960w&quot; /&gt;
  &lt;source type=&quot;image/jpeg&quot; srcset=&quot;https://12daysofweb.dev/img/wreath-w_200.jpg 200w, https://12daysofweb.dev/img/wreath-w_660.jpg 660w, https://12daysofweb.dev/img/wreath-w_960.jpg 960w&quot; /&gt;
  &lt;img src=&quot;https://12daysofweb.dev/img/wreath-w_660.jpg&quot; alt=&quot;A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.&quot; width=&quot;960&quot; height=&quot;640&quot; /&gt;
&lt;/picture&gt;

&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. Et exercitationem sint quis ullam quae, vitae libero doloremque dolores reprehenderit, fugit totam quisquam. Eum nostrum incidunt quas expedita nobis suscipit et!&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;You can take this method one step further since the &lt;code&gt;source&lt;/code&gt; elements also support the &lt;code&gt;sizes&lt;/code&gt; attribute. Note that you can only select a combo of either &lt;code&gt;media&lt;/code&gt; and &lt;code&gt;srcset&lt;/code&gt;, or &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;boosting-css-background-images-with-image-set&quot;&gt;Boosting CSS background images with image-set&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#boosting-css-background-images-with-image-set&quot; aria-labelledby=&quot;boosting-css-background-images-with-image-set&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are certainly reasons why adding an inline image may not be feasible due to using a CMS or other systems without full control over the HTML. In the cases where you at least have CSS control, you can still start to get some benefits similar to &lt;code&gt;srcset&lt;/code&gt; by using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set()&quot; rel=&quot;noopener noreferrer&quot;&gt;the CSS function &lt;code&gt;image-set&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Rather than supply widths, the available option is to mark a resolution such as &lt;code&gt;1x&lt;/code&gt; and &lt;code&gt;2x&lt;/code&gt;. The browser will choose the best match including assessing the resolution as a proxy to assume a lower resolution will be more efficient for low bandwidth. &lt;/p&gt;&lt;p&gt;There is also a &lt;code&gt;type&lt;/code&gt; value for defining modern image formats but &lt;a href=&quot;https://caniuse.com/css-image-set&quot; rel=&quot;noopener noreferrer&quot;&gt;it doesn&amp;#39;t have sufficient support&lt;/a&gt; yet. However, browsers that support &lt;code&gt;image-set()&lt;/code&gt; also support &lt;code&gt;webp&lt;/code&gt; format so we can use &lt;code&gt;webp&lt;/code&gt; in &lt;code&gt;image-set()&lt;/code&gt; as well as a fallback of a regular &lt;code&gt;background-image&lt;/code&gt; with a &lt;code&gt;jpg&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For the current best support, we need to include the &lt;code&gt;-webkit&lt;/code&gt; prefixed version as well:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.image-set&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-repeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wreath-w_660.jpg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;-webkit-image-set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wreath-w_660.webp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; 1x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wreath-w_960.webp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; 2x&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image-set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wreath-w_660.webp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; 1x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wreath-w_960.webp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; 2x&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will behave differently than &lt;code&gt;srcset&lt;/code&gt; since we can only give a hint at the resolution. But being able to draw out the more modern image format (even if a bit hacky right now) can still be worthwhile savings.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;styling-picture-as-a-background-image&quot;&gt;Styling picture as a background image&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#styling-picture-as-a-background-image&quot; aria-labelledby=&quot;styling-picture-as-a-background-image&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Thanks to modern CSS, we can mix up the best of all the techniques to enable using &lt;code&gt;picture&lt;/code&gt; with modern formats and &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; as a background. The other benefit we&amp;#39;ll get is being able to retain &lt;code&gt;alt&lt;/code&gt; descriptions which are lost as a side effect of actual CSS &lt;code&gt;background-image&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s the HTML setup for this effect:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;background-picture&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;   &lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;background-picture__content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Yay background picture!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_200.webp 200w, wreath-w_660.webp 660w, wreath-w_960.webp 960w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/jpeg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_200.jpg 200w, wreath-w_660.jpg 660w, wreath-w_960.jpg 960w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wreath-w_660.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;960&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;640&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To accomplish placing the text over the &lt;code&gt;picture&lt;/code&gt;, we&amp;#39;ll use CSS grid and a trick we first learned for the &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/&quot;&gt;Day 6 holiday card generator&lt;/a&gt; for stacking elements.&lt;/p&gt;&lt;p&gt;Additionally, we&amp;#39;ve added one of my favorite CSS properties, &lt;code&gt;object-fit&lt;/code&gt;, which makes the &lt;code&gt;img&lt;/code&gt; behave as the container for its own contents. In other words, we gain the behavior of &lt;code&gt;background-size&lt;/code&gt; but on a regular inline image.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;For more examples to help learn &lt;code&gt;object-fit&lt;/code&gt;, &lt;a href=&quot;https://5t3ph.dev/egobjfit&quot; rel=&quot;noopener noreferrer&quot;&gt;watch my egghead lesson&lt;/a&gt;.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;You can even sprinkle in some art direction by using the companion property &lt;code&gt;object-position&lt;/code&gt; which you can experiment with using my web app &lt;a href=&quot;https://objectfit-focalpoint.netlify.app/&quot; rel=&quot;noopener noreferrer&quot;&gt;Object-Fit Focal Point&lt;/a&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    .background-picture {
  display: grid;
  /* create a single named grid area */
  grid-template-areas: &quot;bp&quot;;
}

.background-picture &gt; * {
  /* assign all direct children to the single grid area */
  grid-area: bp;
}

.background-picture__content {
  align-self: center;
  /* bring above picture when picture is last in DOM order */
  z-index: 1;
  color: #fff;
  text-align: center;
  font-size: clamp(1.35rem, 5vw, 1.75rem);
  font-weight: bold;
  padding: 5vh 1rem;
}

.background-picture :is(img, picture) {
  display: block;
}

.background-picture img {
  object-fit: cover;
  width: 100%;
  height: 100%;
  /* decrease brightness to improve text contrast */
  filter: brightness(0.65) saturate(1.25);
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Using CSS grid to stack content over the picture element&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.background-picture&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* create a single named grid area */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.background-picture &gt; *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* assign all direct children to the single grid area */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.background-picture__content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* bring above picture when picture is last in DOM order */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.35rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5vw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.75rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5vh 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.background-picture :is(img, picture)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.background-picture img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* decrease brightness to improve text contrast */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.65&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saturate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1.25&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;background-picture&quot;&gt;
  &lt;div class=&quot;background-picture__content&quot;&gt;
    &lt;p&gt;Yay background picture!
  &lt;/p&gt;&lt;/div&gt;
&lt;picture&gt;
  &lt;source type=&quot;image/webp&quot; srcset=&quot;https://12daysofweb.dev/img/wreath-w_200.webp 200w, https://12daysofweb.dev/img/wreath-w_660.webp 660w, https://12daysofweb.dev/img/wreath-w_960.webp 960w&quot; /&gt;
  &lt;source type=&quot;image/jpeg&quot; srcset=&quot;https://12daysofweb.dev/img/wreath-w_200.jpg 200w, https://12daysofweb.dev/img/wreath-w_660.jpg 660w, https://12daysofweb.dev/img/wreath-w_960.jpg 960w&quot; /&gt;
  &lt;img src=&quot;https://12daysofweb.dev/img/wreath-w_660.jpg&quot; alt=&quot;A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.&quot; width=&quot;960&quot; height=&quot;640&quot; /&gt;
&lt;/picture&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;The demo also includes a succinct bonus modern CSS technique to improve text contrast over the image by reducing its brightness with a filter. We also bumped up the saturation to prevent completely losing the image&amp;#39;s vibrancy. You could take this a step further and manage the &lt;code&gt;brightness&lt;/code&gt; and &lt;code&gt;saturate&lt;/code&gt; values with &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/&quot;&gt;custom properties&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;aligning-the-content-over-the-background-picture&quot;&gt;Aligning the content over the background picture&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#aligning-the-content-over-the-background-picture&quot; aria-labelledby=&quot;aligning-the-content-over-the-background-picture&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To change from a centered alignment, you can place the content using the &lt;code&gt;-self&lt;/code&gt; alignment properties available for CSS grid.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Horizontally along the X-axis with &lt;code&gt;justify-self&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Vertically along the Y-axis with &lt;code&gt;align-self&lt;/code&gt; (current style, set to &lt;code&gt;center&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Set both axes at once with &lt;code&gt;place-self&lt;/code&gt;, ex. &lt;code&gt;place-self: end&lt;/code&gt; would put the content in the bottom right corner&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-on-image-display-and-performance&quot;&gt;Additional resources on image display and performance&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/image-display-elements/#additional-resources-on-image-display-and-performance&quot; aria-labelledby=&quot;additional-resources-on-image-display-and-performance&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Understanding the elements we&amp;#39;ve reviewed, when to use them, and how to construct the attribute values is a complicated venture. Here are some additional recommended resources to help guide you to a scenario that works best for you.&lt;/p&gt;&lt;p&gt;First, I highly encourage you to review the MDN docs on each element:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture&quot; rel=&quot;noopener noreferrer&quot;&gt;picture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source&quot; rel=&quot;noopener noreferrer&quot;&gt;source&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img&quot; rel=&quot;noopener noreferrer&quot;&gt;img&lt;/a&gt; (Yes, really! I&amp;#39;m positive you&amp;#39;ll learn something!)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Additionally, MDN has &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images&quot; rel=&quot;noopener noreferrer&quot;&gt;an excellent guide to responsive images&lt;/a&gt; that provides more demos of the things we touched on in this article.&lt;/p&gt;&lt;p&gt;Two tools to help prepare images:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://responsivebreakpoints.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Responsive Image Breakpoints Generator&lt;/a&gt; from Cloudinary&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://squoosh.app/&quot; rel=&quot;noopener noreferrer&quot;&gt;Squoosh app&lt;/a&gt; to convert between image types and adjust optimization&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Still confused on when to use which type? Read these resources to help you understand... well, the bigger picture 😉&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/responsive-images-youre-just-changing-resolutions-use-srcset/&quot; rel=&quot;noopener noreferrer&quot;&gt;Chris Coyier dropping knowledge and advice&lt;/a&gt; in 2014/15 that still holds up (that&amp;#39;s the nice thing about HTML!)&lt;/li&gt;&lt;li&gt;And more recently, Chris created a &lt;a href=&quot;https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/&quot; rel=&quot;noopener noreferrer&quot;&gt;guide to responsive image syntax&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Eric Portis wrote this absolutely stunning article (coincidentally also in 2014) that is exceptional at &lt;a href=&quot;https://ericportis.com/posts/2014/srcset-sizes/&quot; rel=&quot;noopener noreferrer&quot;&gt;explaining the srcset and sizes attributes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;More recently, &lt;a href=&quot;https://www.smashingmagazine.com/2021/04/humble-img-element-core-web-vitals/&quot; rel=&quot;noopener noreferrer&quot;&gt;Addy Osmani covered a lot about images&lt;/a&gt; as well as the relationship to Core Web Vitals (and he wrote an entire book dedicated to Image Optimization which you can find at the end of that article)&lt;/li&gt;&lt;li&gt;The HTML spec includes &lt;a href=&quot;https://html.spec.whatwg.org/multipage/images.html#introduction-3&quot; rel=&quot;noopener noreferrer&quot;&gt;guidance on a whole series of responsive image scenarios&lt;/a&gt; with example code&lt;/li&gt;&lt;li&gt;Learn about &lt;a href=&quot;https://web.dev/learn/design/responsive-images/&quot; rel=&quot;noopener noreferrer&quot;&gt;responsive images and the picture element&lt;/a&gt; in the Responsive Design module from web.dev&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Preference Queries</title>
    <link href="https://12daysofweb.dev/2021/preference-queries/"/>
    <updated>2021-12-19T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/preference-queries/</id>
    <content type="html">



&lt;p&gt;You may be familiar with media queries to detect a user&amp;#39;s viewport resolution, like the following:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Styles for viewports larger than 60rem */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But did you know that &lt;code&gt;@media&lt;/code&gt; - also known as one of the CSS at-rules - contains 24 total features to query against? Review the whole &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media#media_features&quot; rel=&quot;noopener noreferrer&quot;&gt;list of &lt;code&gt;@media&lt;/code&gt; features on MDN&lt;/a&gt;, and check the browser support table (about 19 have decent cross-browser support).&lt;/p&gt;&lt;p&gt;The two we&amp;#39;ll be covering have to do with user preferences - as in, features that are determined by operating system settings.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;about-prefers-reduced-motion&quot;&gt;About prefers-reduced-motion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#about-prefers-reduced-motion&quot; aria-labelledby=&quot;about-prefers-reduced-motion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion&quot; rel=&quot;noopener noreferrer&quot;&gt;As MDN states&lt;/a&gt;, this preference query &amp;quot;is used to detect if the user has requested that the system minimize the amount of non-essential motion it uses.&amp;quot;&lt;/p&gt;&lt;p&gt;I&amp;#39;ve been a developer for nearly 15 years, and over that time I&amp;#39;ve seen a lot of trends. One with a significant amount of staying power was parallax animation, thanks to being boosted by big brands like Nike and Apple.&lt;/p&gt;&lt;p&gt;Parallax animation is a good example of a harmful type of motion for users with vestibular disorders. This is due to the foreground and background moving at different rates, which for some users can cause dizziness, nausea, and headaches. As Val Head notes in &lt;a href=&quot;http://alistapart.com/article/designing-safer-web-animation-for-motion-sensitivity/&quot; rel=&quot;noopener noreferrer&quot;&gt;Designing Safer Web Animation for Motion Sensitivities&lt;/a&gt;, the negative effects for some users can last long after they&amp;#39;ve seen the animation.&lt;/p&gt;&lt;p&gt;With the use of &lt;code&gt;prefers-reduced-motion&lt;/code&gt;, we can take steps towards reducing the impact of potentially harmful animations.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-prefers-reduced-motion&quot;&gt;Using prefers-reduced-motion&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#using-prefers-reduced-motion&quot; aria-labelledby=&quot;using-prefers-reduced-motion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are two keywords for determining the state of a user&amp;#39;s setting related to reduced motion that is surfaced via prefers-reduced-motion:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;no-preference&lt;/code&gt; - the default, which &lt;a href=&quot;https://www.tatianamac.com/posts/prefers-reduced-motion/&quot; rel=&quot;noopener noreferrer&quot;&gt;as Tatiana Mac suggests&lt;/a&gt; may mean a user is ok with motion or that they aren&amp;#39;t aware an option exists to reduce motion&lt;/li&gt;&lt;li&gt;&lt;code&gt;reduce&lt;/code&gt; - a user has explicitly set their OS system setting for a reduced motion experience&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And here&amp;#39;s an example of setting both types. You can adjust this setting via your OS, or in Chromium dev tools &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-79/#userpreferences&quot; rel=&quot;noopener noreferrer&quot;&gt;it can be emulated under the &amp;quot;Rendering&amp;quot; tab&lt;/a&gt;.&lt;/p&gt;
    

    
    &lt;style&gt;
    @media (prefers-reduced-motion: no-preference) {
  .shake:hover {
    animation: shake 400ms ease-in-out;
  }
}

@media (prefers-reduced-motion: reduce) {
  .shake {
    /* !important due to overriding this site&#39;s rules to
    remove transitions when meeting this condition */
    transition: transform 180ms ease-in !important;
  }

  .shake:hover {
    transform: translateX(.25rem);
  }
}

@keyframes shake {
  0%, 100% {
    transform: translateX(0.5rem);
  }
  50% {
    transform: translateX(-0.5rem);
  }
}

.shake {
  font-size: 1.35rem;
  font-weight: bold;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demo of using prefers-reduced-motion&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.shake:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; shake 400ms ease-in-out&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; reduce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.shake&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* !important due to overriding this site&#39;s rules to&lt;br /&gt;    remove transitions when meeting this condition */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform 180ms ease-in &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.shake:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.25rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; shake&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;0%, 100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;50%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-0.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.shake&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.35rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;shake&quot;&gt;Shake on hover if motion allowed&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;If you are using many animations, you can instead place them all in their own stylesheet and conditionally load it in via the &lt;code&gt;media&lt;/code&gt; attribute on the &lt;code&gt;link&lt;/code&gt; element:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&amp;lt;link rel=&lt;span class=&quot;token string&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; href=&lt;span class=&quot;token string&quot;&gt;&quot;animations.css&quot;&lt;/span&gt;&lt;br /&gt;  media=&lt;span class=&quot;token string&quot;&gt;&quot;(prefers-reduced-motion: no-preference)&quot;&lt;/span&gt;&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or, if you have only some minimal animations or transitions, you can borrow a technique popularized from &lt;a href=&quot;https://piccalil.li/blog/a-modern-css-reset/&quot; rel=&quot;noopener noreferrer&quot;&gt;Andy Bell&amp;#39;s modern CSS reset&lt;/a&gt;. This fast-forwards animations and transitions when a user prefers reduced motion.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; reduce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;*,&lt;br /&gt;  *::before,&lt;br /&gt;  *::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.01ms &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation-iteration-count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1 &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transition-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.01ms &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;scroll-behavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Why not completely remove them? Because there are times when a script may be listening for the &lt;code&gt;transitionend&lt;/code&gt; or &lt;code&gt;animationend&lt;/code&gt; events so it&amp;#39;s safer to allow an imperceptible duration.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;handling-prefers-reduced-motion-with-javascript&quot;&gt;Handling prefers-reduced-motion with JavaScript&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#handling-prefers-reduced-motion-with-javascript&quot; aria-labelledby=&quot;handling-prefers-reduced-motion-with-javascript&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There is also a JavaScript way to detect the value of &lt;code&gt;prefers-reduced-motion&lt;/code&gt;, which is beneficial if your animations are JS controlled.&lt;/p&gt;&lt;p&gt;In the following snippet, we&amp;#39;re checking if &lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt; matches. If it does match, then &lt;code&gt;prefersReducedMotion&lt;/code&gt; will evaluate to true meaning the user prefers reduced motion.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; motionMQ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(prefers-reduced-motion: reduce)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefersReducedMotion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; motionMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can then extend that to listen in case that preference changes so we can adapt the experience accordingly.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;motionMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;change&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleMotionChange&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this demo, the text will be set according to your preference and update if you toggle your motion setting.&lt;/p&gt;
    

    
    &lt;style&gt;
    .mq-element { font-size: 1.35rem; }
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Detecting prefers-reduced-motion in JS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.mq-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.35rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; motionMQ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(prefers-reduced-motion: reduce)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;updateMQ&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;reduced&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.mq-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reduced&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;reduce&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;no preference&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update on load&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;updateMQ&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;motionMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update on change&lt;/span&gt;&lt;br /&gt;motionMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;change&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;updateMQ&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;motionMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;mq-element&quot;&gt;...&lt;/p&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const motionMQ = window.matchMedia(&#39;(prefers-reduced-motion: reduce)&#39;);

const updateMQ = (reduced) =&gt; {
  const element = document.querySelector(&#39;.mq-element&#39;);
  if (reduced) {
    element.textContent = &#39;reduce&#39;;
  } else {
    element.textContent = &#39;no preference&#39;;
  }
};

// Update on load
updateMQ(motionMQ.matches);

// Update on change
motionMQ.addEventListener(&#39;change&#39;, () =&gt; {
  updateMQ(motionMQ.matches);
});
    
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;additional-resources-on-prefers-reduced-motion&quot;&gt;Additional resources on prefers-reduced-motion&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#additional-resources-on-prefers-reduced-motion&quot; aria-labelledby=&quot;additional-resources-on-prefers-reduced-motion&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Learn more about the related &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/animation-from-interactions.html&quot; rel=&quot;noopener noreferrer&quot;&gt;WCAG Success Criterion 2.3.3: Animation from interactions&lt;/a&gt; which gives more context into why it&amp;#39;s important to reduce animations&lt;/li&gt;&lt;li&gt;Eric Bailey gives a bit more history and a demo in his &lt;a href=&quot;https://css-tricks.com/introduction-reduced-motion-media-query/&quot; rel=&quot;noopener noreferrer&quot;&gt;introduction to the reduced motion media query&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Val Head presenting &lt;a href=&quot;https://aneventapart.com/news/post/making-motion-inclusive-aea-video&quot; rel=&quot;noopener noreferrer&quot;&gt;Making Motion Inclusive&lt;/a&gt; at An Event Apart demonstrates how reduced motion doesn&amp;#39;t mean no animations allowed&lt;/li&gt;&lt;li&gt;Lindsey Kopacz walks through &lt;a href=&quot;https://www.a11ywithlindsey.com/blog/reducing-motion-improve-accessibility&quot; rel=&quot;noopener noreferrer&quot;&gt;creating a toggle&lt;/a&gt; to allow your users to choose a reduced motion experience instead of only relying on the preference query&lt;/li&gt;&lt;li&gt;Josh Comeau looks at &lt;a href=&quot;https://www.joshwcomeau.com/react/prefers-reduced-motion/&quot; rel=&quot;noopener noreferrer&quot;&gt;using prefers-reduced-motion in React&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-prefers-color-scheme&quot;&gt;Using prefers-color-scheme&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#using-prefers-color-scheme&quot; aria-labelledby=&quot;using-prefers-color-scheme&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The second preference query you may have heard of since it is associated with providing a dark mode version of your site.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;prefers-color-scheme&lt;/code&gt; media feature does in fact detect whether a user has requested a dark or light theme.&lt;/p&gt;&lt;p&gt;While this often gets bundled up by developers into a face-off similar to tabs vs. spaces, the matter of dark or light has a lot to do with accessibility. For example, I myself preferred a light theme for years until I learned I had astigmatism which was making dark themes uncomfortable due to the appearance of &amp;quot;halos&amp;quot; around the letters.&lt;/p&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;A related upcoming feature query that is gaining browser support is &lt;code&gt;prefers-contrast&lt;/code&gt; which detects &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast&quot; rel=&quot;noopener noreferrer&quot;&gt;whether a user prefers more or less contrast&lt;/a&gt;. Keep this on your radar going into 2022!&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;The options for this query are fairly self-explanatory:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;light&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;dark&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Keep in mind that these are not expected to be as polar as white vs. black, but more about increasing the use of light or dark colors particularly for large areas of text.&lt;/p&gt;&lt;p&gt;A nifty way to manage your themes is by using CSS custom properties (&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/&quot;&gt;covered in Day 3&lt;/a&gt;). By choosing general-purpose names for your custom property colors and using them carefully throughout your stylesheets, you can flip their values to retheme your site when either dark or light is requested.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-background&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following demo shows a minimal example of this idea in action. Once again you can change your user settings or test this via dev tools as noted for the previous section.&lt;/p&gt;
    

    
    &lt;style&gt;
    .site {
  --theme: &quot;Light&quot;;
  --theme-background: lightblue;
  --theme-text: #222;
  --theme-inverse: #f9f9f9;
  --theme-primary: blue;

  background-color: var(--theme-background);
  color: var(--theme-text);
  padding: 1rem;
}

@media (prefers-color-scheme: dark) {
  .site {
    --theme: &quot;Dark&quot;;
    --theme-background: #222;
    --theme-text: #f9f9f9;
    --theme-inverse: #444;
    --theme-primary: cyan;
  }
}

.site article {
  width: min(40ch, 100%);
  margin: 0 auto;
  padding: 1rem;
  background-color: var(--theme-inverse);
}

.site article * {
  margin: 0;
}

.site article * + * {
  margin-top: 1em;
}

.site article h2::after {
  content: &quot; &quot; var(--theme);
}

.site a:not([class]) {
  color: var(--theme-primary);
}

.site-btn {
  display: inline-block;
  text-decoration: none;
  background-color: var(--theme-primary);
  color: var(--theme-inverse);
  padding: 0.5em 0.75em;
  border-radius: 0.25em;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Demo of theming with prefers-color-scheme&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.site&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Light&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-inverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f9f9f9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--theme-primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-background&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.site&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Dark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f9f9f9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-inverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #444&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--theme-primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cyan&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-inverse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site article *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site article * + *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site article h2::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site a:not([class])&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-primary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.site-btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-primary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--theme-inverse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em 0.75em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;site&quot;&gt;
  &lt;article&gt;
    &lt;h2&gt;Theme Demo&lt;/h2&gt;
    &lt;p&gt;Lorem ipsum dolor, sit amet consectetur adipisicing elit. Exercitationem amet magnam corrupti!&lt;/p&gt;
    &lt;p&gt;Magnam, a. Delectus consectetur hic at? Consequuntur maxime &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/&quot;&gt;hic repellat numquam&lt;/a&gt; culpa.&lt;/p&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/&quot; class=&quot;site-btn&quot;&gt;Button&lt;/a&gt;
  &lt;/article&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;handling-prefers-color-scheme-with-javascript&quot;&gt;Handling prefers-color-scheme with JavaScript&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#handling-prefers-color-scheme-with-javascript&quot; aria-labelledby=&quot;handling-prefers-color-scheme-with-javascript&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We can detect and use the &lt;code&gt;prefers-color-scheme&lt;/code&gt; value in a nearly identical format to &lt;code&gt;prefers-reduced-motion&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This demo also includes a different option for managing color themes via CSS custom properties.&lt;/p&gt;
    

    
    &lt;style&gt;
    .theme-element {
  background: var(--background, white);
  color: var(--color, black);
  border: 1px solid;
  padding: 2rem;
  font-size: 1.35rem;
}

@media (prefers-color-scheme: dark) {
  .theme-element {
    --background: #222;
    --color: white;
  }
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Detecting prefers-color-scheme in JS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.theme-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--background&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.35rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.theme-element&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; themeMQ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(prefers-color-scheme: dark)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;updateTheme&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.theme-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dark theme&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;light theme&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update on load&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;updateTheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;themeMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update on change&lt;/span&gt;&lt;br /&gt;themeMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;change&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;updateTheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;themeMQ&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;theme-element&quot;&gt;...&lt;/p&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const themeMQ = window.matchMedia(&#39;(prefers-color-scheme: dark)&#39;);

const updateTheme = (dark) =&gt; {
  const element = document.querySelector(&#39;.theme-element&#39;);
  if (dark) {
    element.textContent = &#39;dark theme&#39;;
  } else {
    element.textContent = &#39;light theme&#39;;
  }
};

// Update on load
updateTheme(themeMQ.matches);

// Update on change
themeMQ.addEventListener(&#39;change&#39;, () =&gt; {
  updateTheme(themeMQ.matches);
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;additional-resources-on-prefers-color-scheme&quot;&gt;Additional resources on prefers-color-scheme&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/preference-queries/#additional-resources-on-prefers-color-scheme&quot; aria-labelledby=&quot;additional-resources-on-prefers-color-scheme&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Accessibility expert Adrian Roselli reminds us that when building a theme toggle, &lt;a href=&quot;https://twitter.com/aardrian/status/1385210854715629569&quot; rel=&quot;noopener noreferrer&quot;&gt;there are really three options&lt;/a&gt;: light, dark, and inherit from system preferences&lt;/li&gt;&lt;li&gt;Andy Bell walks through &lt;a href=&quot;https://piccalil.li/tutorial/create-a-user-controlled-dark-or-light-mode/&quot; rel=&quot;noopener noreferrer&quot;&gt;one way to make a toggle&lt;/a&gt; including saving a user&amp;#39;s selection to &lt;code&gt;localStorage&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A few posts on setting up dark and light themes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Michelle Barker covers &lt;a href=&quot;https://css-irl.info/quick-and-easy-dark-mode-with-css-custom-properties/&quot; rel=&quot;noopener noreferrer&quot;&gt;the custom property way to switch themes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Christopher Kirk-Nielsen&lt;strong&gt; &lt;/strong&gt;offers &lt;a href=&quot;https://css-tricks.com/a-dry-approach-to-color-themes-in-css/&quot; rel=&quot;noopener noreferrer&quot;&gt;a DRY approach for managing themes&lt;/a&gt; that is flexible for more than two options&lt;/li&gt;&lt;li&gt;The Material Design guidelines are worth a glance for different &lt;a href=&quot;https://material.io/design/color/dark-theme.html#properties&quot; rel=&quot;noopener noreferrer&quot;&gt;things to consider when developing a dark theme&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Capturing User Media Streams</title>
    <link href="https://12daysofweb.dev/2021/capturing-user-media-streams/"/>
    <updated>2021-12-18T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/capturing-user-media-streams/</id>
    <content type="html">



&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices&quot; rel=&quot;noopener noreferrer&quot;&gt;MediaDevices interface&lt;/a&gt; allows accessing a user&amp;#39;s webcam and microphone, as well as allowing screen sharing. It requires a secure connection and prompts the user for permission after which the output - aka &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MediaStream&quot; rel=&quot;noopener noreferrer&quot;&gt;MediaStream&lt;/a&gt; - can be used within your application.&lt;/p&gt;&lt;p&gt;We&amp;#39;ll specifically be learning how to use &lt;code&gt;getUserMedia()&lt;/code&gt; to stream a user&amp;#39;s webcam video and compose it with an SVG inside of HTML canvas to generate a screenshot, like mine!&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/12daysofwebdev/5a5ec021-da81-40fd-9801-221c0452e0ab_12DaysHolidayCard.jpeg?auto=compress,format&quot; alt=&quot;Stephanie is smiling at the camera within an illustrated frame of confetti triangles on top, a mug of cocoa with a candy cane inside, and the text Feeling Jolly 12DaysOfWeb.dev&quot; /&gt;&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;requesting-and-displaying-a-video-media-stream&quot;&gt;Requesting and displaying a video media stream&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#requesting-and-displaying-a-video-media-stream&quot; aria-labelledby=&quot;requesting-and-displaying-a-video-media-stream&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are a few essential parts of requesting a media stream, as in a user&amp;#39;s video source like a webcam and/or an audio source like from a microphone.&lt;/p&gt;&lt;p&gt;The starting point is a call to &lt;code&gt;navigator.mediaDevices.getUserMedia()&lt;/code&gt; along with an object holding the requested &amp;quot;constraints.&amp;quot; The constraints include which types of media streams you would like - video and or audio - and other features like preferred dimensions. For the purposes of our holiday card, we&amp;#39;re also going to request the front-facing camera as the preferred.&lt;/p&gt;&lt;p&gt;A Promise is returned from &lt;code&gt;getUserMedia()&lt;/code&gt; along with the media stream if successful. The media stream can contain multiple &amp;quot;tracks&amp;quot; for each of audio and video sources.&lt;/p&gt;&lt;p&gt;We can wrap up the minimal required pieces as follows:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSuccess&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; video &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;video&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;srcObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Error: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;startWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mediaDevices&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUserMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleSuccess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In your HTML you would have an empty &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element, and a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; to trigger &lt;code&gt;startWebcam()&lt;/code&gt;, such as:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;video&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;autoplay&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;muted&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;playsinline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;video&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;startWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Start Webcam&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is of course missing some important features, particularly the way to stop the webcam, but if you&amp;#39;d like you can test this in something like CodePen. If you haven&amp;#39;t previously given your localhost or CodePen access to your webcam, your browser will display a prompt for you to give permission.&lt;/p&gt;&lt;p&gt;We also placed a few attributes on the video element which are critical to the streaming working cross-platform. The &lt;code&gt;autoplay&lt;/code&gt; attribute prepares the video element so that as soon as it receives the stream it will play it back live. The &lt;code&gt;muted&lt;/code&gt; and &lt;code&gt;playsinline&lt;/code&gt; attributes are primarily to ensure the stream successfully plays back on iOS, as described in their &lt;a href=&quot;https://webkit.org/blog/6784/new-video-policies-for-ios/&quot; rel=&quot;noopener noreferrer&quot;&gt;video policies announcement.&lt;/a&gt;&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;holiday-card-generator-process&quot;&gt;Holiday card generator process&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#holiday-card-generator-process&quot; aria-labelledby=&quot;holiday-card-generator-process&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Our initial display will position the SVG of the card frame illustration over the video element. Then, when a user selects &amp;quot;Start webcam&amp;quot;, they&amp;#39;ll see a preview of what their holiday card screenshot will look like. &lt;/li&gt;&lt;li&gt;Once they select &amp;quot;Take Photo&amp;quot;, we&amp;#39;ll stop the video and pass the video stream and SVG into HTML Canvas which has a method that we can use to set the composite as the &lt;code&gt;src&lt;/code&gt; of the image. &lt;/li&gt;&lt;li&gt;The user can then save the screenshot like any other image on the web. &lt;/li&gt;&lt;li&gt;If they want to retake, they can again select &amp;quot;Start Webcam&amp;quot; and we&amp;#39;ll reset the image &lt;code&gt;src&lt;/code&gt; to the SVG frame. &lt;/li&gt;&lt;li&gt;Additionally, we&amp;#39;ll flip the start action to stop so that they can cancel the video access without taking a screenshot.&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;holiday-card-html-and-css&quot;&gt;Holiday card HTML and CSS&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#holiday-card-html-and-css&quot; aria-labelledby=&quot;holiday-card-html-and-css&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Our generator has two sections: one to hold the card display, and one to hold the action buttons.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;video&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card__video&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;autoplay&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;muted&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;playsinline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;video&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card__img&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/12DaysCardFrame.svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card__actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-webcam-instructions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Webcam required to enable taking a photo for the holiday card&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card-webcam&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-describedby&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-webcam-instructions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-state&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;offline&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Start Webcam&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;holiday-card-photo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Take Photo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;#39;ve included a few features for accessibility by adding some instructions so that non-sighted users will get a bit more context for why there is a &amp;quot;Start Webcam&amp;quot; button. These users have a few modes of navigation including tabbing between interactive elements and scanning text content. In scan mode, they&amp;#39;ll receive the instructions first due to the DOM order. In tabbing mode the button name will be read first, then the instructions due to the association created by &lt;code&gt;aria-describedby&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Since &amp;quot;Take Photo&amp;quot; cannot perform any action until the webcam stream is available, we have set the &lt;code&gt;disabled&lt;/code&gt; attribute.&lt;/p&gt;&lt;p&gt;On the webcam button, we&amp;#39;ve added the &lt;code&gt;data-state&lt;/code&gt; attribute so we can keep track of whether the webcam is currently &lt;code&gt;offline&lt;/code&gt; or &lt;code&gt;streaming&lt;/code&gt;.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;holiday-card-styles&quot;&gt;Holiday card styles&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#holiday-card-styles&quot; aria-labelledby=&quot;holiday-card-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;We&amp;#39;ll be using CSS Grid and &lt;a href=&quot;https://smolcss.dev/#smol-stack-layout&quot; rel=&quot;noopener noreferrer&quot;&gt;one of my favorite tricks&lt;/a&gt; to stack elements within a single grid cell in order to place the SVG image frame above the video. This technique is an upgrade from using the less flexible solution of absolute positioning.&lt;/p&gt;&lt;p&gt;The relevant styles for stacking the video and image with grid are as follows:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__video,&lt;br /&gt;.holiday-card__img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; card&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Through testing, I found relative positioning was necessary to ensure the image appeared above the video element.&lt;/p&gt;&lt;p&gt;While I won&amp;#39;t go over every line in the styles, another key part is where we&amp;#39;ve set the &lt;code&gt;.holiday-card&lt;/code&gt; wrapper to use &lt;code&gt;aspect-ratio: 16/9&lt;/code&gt;. We&amp;#39;re going to be requesting a video feed in HD format. The CSS property for &lt;code&gt;aspect-ratio&lt;/code&gt; has seen increased support over just this past year, but we want to provide a fallback if it&amp;#39;s not yet supported.&lt;/p&gt;&lt;p&gt;For that, we&amp;#39;ll use a combination of the native CSS &lt;code&gt;@supports&lt;/code&gt; feature and a custom property for setting the element&amp;#39;s &lt;code&gt;max-height&lt;/code&gt;. We&amp;#39;ll update that value with JavaScript so that we can ensure it ends up with the &lt;code&gt;16/9&lt;/code&gt; aspect ratio. We&amp;#39;ll do that part when we complete our generator script.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16/9&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.holiday-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--card-height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 30vh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Jump back to &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/&quot;&gt;Day 3 all about custom properties&lt;/a&gt; if you&amp;#39;re unfamiliar with this syntax!&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;Here&amp;#39;s our styled card application with some other goodies like candy cane striping.&lt;/p&gt;
    

    
    &lt;style&gt;
    .demo {
  background-color: lightblue;
}

[class*=&quot;holiday-card&quot;] {
  margin: 0;
}

.holiday-card {
  display: grid;
  place-items: center;
  grid-template-areas: &quot;card&quot;;
  background-color: #222;
  aspect-ratio: 16/9;
  width: 100%;
  border-radius: 2rem 2rem 0 0;
  overflow: hidden;
}

@supports not (aspect-ratio: 16/9) {
  .holiday-card {
    max-height: var(--card-height, 30vh);
  }
}

.holiday-card__video,
.holiday-card__img {
  grid-area: card;
  display: block;
  max-width: 100%;
  max-height: 100%;
  /* required to prevent mobile portrait overflow */
  overflow: hidden;
}

.holiday-card__img {
  position: relative;
  width: 100%;
}

.holiday-card__actions {
  --color-green: #30a45e;
  --color-red: #e63a48;
  --color-light: #fcdce2;

  display: grid;
  grid-auto-flow: column;
  justify-content: center;
  gap: min(2rem, 4vw);
  padding: clamp(.5rem, 5%, 1rem);
  background: #e63a48;
  background-image: repeating-linear-gradient(45deg, var(--color-red) 0 2%, var(--color-light) 2% 5%);
  border-radius: 0 0 2rem 2rem;
  box-shadow: 0 0.5rem 0.5rem -0.25rem rgba(0, 0, 0, 0.35);
}

.holiday-card__actions button {
  all: unset;
  cursor: pointer;
  text-align: center;
  border-radius: 0.5em;
  border: 0.15em solid var(--color-light);
  color: #fff;
  background-color: var(--color-red);
  padding: 0.5em 0.75em;
  font-family: system-ui, sans-serif;
  font-size: 1.25rem;
  font-weight: bold;
  letter-spacing: 0.03em;
  box-shadow: 0.1em 0.15em 0.25em -0.08em rgba(0, 0, 0, 0.75);
}

.holiday-card__actions button:focus {
  outline: 2px dashed currentcolor;
  outline-offset: -7px;
}

.holiday-card__actions button:not(:disabled):hover {
  background-color: var(--color-green);
}

.holiday-card__actions button:disabled {
  cursor: not-allowed;
  opacity: 0.7;
  filter: grayscale(40%);
  box-shadow: inset 0.1em 0.15em 0.25em -0.08em rgba(0, 0, 0, 0.75);
}

#holiday-webcam-instructions {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Holiday Card Generator CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.demo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;[class*=&quot;holiday-card&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16/9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem 2rem 0 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16/9&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.holiday-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--card-height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 30vh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__video,&lt;br /&gt;.holiday-card__img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; card&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* required to prevent mobile portrait overflow */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__actions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color-green&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #30a45e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color-red&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #e63a48&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color-light&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fcdce2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-auto-flow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; column&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 4vw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.5rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #e63a48&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeating-linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;45deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 0 2%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 2% 5%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0 2rem 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 0.5rem 0.5rem -0.25rem &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.35&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__actions button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.15em solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-red&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5em 0.75em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system-ui&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;letter-spacing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.03em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.1em 0.15em 0.25em -0.08em &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.75&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__actions button:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px dashed currentcolor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -7px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__actions button:not(:disabled):hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-green&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.holiday-card__actions button:disabled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; not-allowed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.7&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grayscale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inset 0.1em 0.15em 0.25em -0.08em &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.75&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#holiday-webcam-instructions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;white-space&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nowrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;holiday-card&quot;&gt;
  &lt;video class=&quot;holiday-card__video&quot; autoplay=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;/video&gt;
  &lt;img class=&quot;holiday-card__img&quot; src=&quot;https://12daysofweb.dev/img/12DaysCardFrame.svg&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;
&lt;div class=&quot;holiday-card__actions&quot;&gt;
  &lt;!-- instructions removed from this demo to prevent duplicate IDs --&gt;
  &lt;button type=&quot;button&quot; class=&quot;holiday-card-webcam&quot; aria-describedby=&quot;holiday-webcam-instructions&quot; data-state=&quot;offline&quot;&gt;Start Webcam&lt;/button&gt;
  &lt;button type=&quot;button&quot; class=&quot;holiday-card-photo&quot; disabled=&quot;&quot;&gt;Take Photo&lt;/button&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;completing-the-generator-script&quot;&gt;Completing the generator script&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#completing-the-generator-script&quot; aria-labelledby=&quot;completing-the-generator-script&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The minimal script we first discussed is our starting point for the final holiday card generator. &lt;/p&gt;&lt;p&gt;With our card HTML now created, let&amp;#39;s first create variables of all the pieces.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; card &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.holiday-card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.holiday-card__img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardVideo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.holiday-card__video&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardWebcamButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.holiday-card-webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardPhotoButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.holiday-card-photo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Recall we also setup a CSS custom property as a fallback for when CSS &lt;code&gt;aspect-ratio&lt;/code&gt; wasn&amp;#39;t supported, and it&amp;#39;s time to supply that value. So now that we have the card element, we can compute the correct height to ensure the &lt;code&gt;16/9&lt;/code&gt; ratio. This will only actually be set as the height if the browser doesn&amp;#39;t support &lt;code&gt;aspect-ratio&lt;/code&gt; due to how we set up the CSS using &lt;code&gt;@supports&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;card&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--card-height&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; card&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetWidth &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5625&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An update to make is to improve the constraints to select for HD resolution and preference the front camera. The &lt;code&gt;ideal&lt;/code&gt; key will request that the device provides the nearest available resolution if available. You can review the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#parameters&quot; rel=&quot;noopener noreferrer&quot;&gt;other available constraint parameters&lt;/a&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; constraints &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ideal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1280&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ideal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;720&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;facingMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSuccess&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;srcObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Error: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;startWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mediaDevices&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUserMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleSuccess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now we&amp;#39;ll add the click event listener to handle starting and stopping the webcam.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; webcamState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webcamState &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;startWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;stopWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The stop function is yet to be created, but it relies on the fact we saved the stream into the &lt;code&gt;window.stream&lt;/code&gt; object. The MediaStream API provides &lt;code&gt;getVideoTracks()&lt;/code&gt; which returns an array of all found video streams. We&amp;#39;re only expecting one, so we then call the &lt;code&gt;stop()&lt;/code&gt; method. This immediately disconnects the video stream and the user&amp;#39;s webcam will become inactive.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;stopWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getVideoTracks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we have the basis of our functions but we haven&amp;#39;t updated the state of our UI elements.&lt;/p&gt;&lt;p&gt;When the webcam is started successfully, we can do a few extra steps within &lt;code&gt;handleSuccess()&lt;/code&gt; to make the &amp;quot;Take Photo&amp;quot; button available and also toggle the webcam button to &amp;quot;Stop&amp;quot; and its state to &lt;code&gt;streaming&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSuccess&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;streaming&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stop Webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardFrame&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;srcObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One more piece slipped in, which was to reset the card img back to the SVG file path, which we need to add as a variable. We&amp;#39;re doing this because when this function is called after the &amp;quot;Take Photo&amp;quot; action, the image source will be the saved screenshot. This is to reset to allow the video stream to be visible.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardFrame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/12DaysCardFrame.svg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Due to Canvas image security policies, you&amp;#39;ll need to serve your frame image from your same domain or ensure cross-origin access is allowed from a subdomain or CDN to successfully use it for the screenshot.&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;We&amp;#39;ll enhance &lt;code&gt;stopWebcam()&lt;/code&gt; to handle the reverse state of the UI.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;stopWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Start Webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getVideoTracks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;create-a-video-screenshot-using-html-canvas&quot;&gt;Create a video screenshot using HTML canvas&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#create-a-video-screenshot-using-html-canvas&quot; aria-labelledby=&quot;create-a-video-screenshot-using-html-canvas&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;With our webcam start and stop working, it&amp;#39;s time to enable taking the screenshot!&lt;/p&gt;&lt;p&gt;First, we need to create a canvas element. This can be added near our UI variables:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardCanvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;canvas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, we&amp;#39;ll start the function within the click event listener for the photo button. We prepare &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; variables that match the video resolution. This might seem like an odd choice, but it makes our final screenshot easier to take. There is a downside for a particular circumstance, which we&amp;#39;ll discuss at the end.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;videoWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;videoHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Setup Canvas&lt;/span&gt;&lt;br /&gt;  cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Those dimensions are applied to the canvas element we created, and then comes the required step of obtaining the 2D context. The context is what we attach our drawing methods to for rendering the video and the frame SVG.&lt;/p&gt;&lt;p&gt;Our first item to render to canvas is the video, which is interestingly done via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage&quot; rel=&quot;noopener noreferrer&quot;&gt;the canvas method of &lt;code&gt;drawImage&lt;/code&gt;&lt;/a&gt;. The zeroes represent the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates for placing the video on the canvas.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Draw video&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cardVideo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Following that, we begin to set up for rendering the SVG. We create a new canvas &lt;code&gt;Image()&lt;/code&gt; and match the dimensions to the canvas. Then, set its source to the SVG file path.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Create frame image&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; frame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardFrame&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;crossOrigin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;crossOrigin&lt;/code&gt; attribute may not be necessary if your image is relative to your site, but might be needed if coming from a CDN. You can learn more about why &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image&quot; rel=&quot;noopener noreferrer&quot;&gt;it might be necessary for canvas images&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Creating the image in this way means it needs to load which requires time just like an image loaded into the DOM. Before we proceed with capturing the screenshot, we&amp;#39;ll wait for the onload event of the image to ensure it&amp;#39;s fully available. Otherwise only the video will be captured.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Ensure frame loaded&lt;/span&gt;&lt;br /&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Draw frame to canvas&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Output final composed canvas to DOM img&lt;/span&gt;&lt;br /&gt;  cardImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;image/jpeg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The comments capture the steps, but after drawing the SVG we conclude the process by rendering the canvas contents as base64 encoded &lt;code&gt;jpeg&lt;/code&gt; data into the card image &lt;code&gt;src&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;We selected &lt;code&gt;jpeg&lt;/code&gt; as the file format so that it retains the video quality as much as possible and so that it is a type that the user can download and use as they wish. There are other &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL&quot; rel=&quot;noopener noreferrer&quot;&gt;options for &lt;code&gt;toDataURL()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To close out the function, we need to trigger stopping the webcam. And since stopping the webcam disables the photo button, we&amp;#39;ll move focus back to the &amp;quot;Start Webcam&amp;quot; button to prevent disorienting assistive technology users since disabled buttons are not focusable.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;stopWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Have fun trying out the generator!&lt;/p&gt;
    

    

    
    &lt;details&gt;
    &lt;summary&gt;Holiday Card Generator Demo&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; constraints &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;video&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ideal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1280&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ideal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;720&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;facingMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardFrame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/img/12DaysCardFrame.svg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Scoped to prevent working on the CSS demo :)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; card &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.scripted.holiday-card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.scripted .holiday-card__img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardVideo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.scripted .holiday-card__video&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardWebcamButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.scripted .holiday-card-webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardPhotoButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.scripted .holiday-card-photo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cardCanvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;canvas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;card&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--card-height&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; card&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetWidth &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5625&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSuccess&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;streaming&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stop Webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardFrame&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;srcObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Error: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;startWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mediaDevices&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUserMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleSuccess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;stopWebcam&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Start Webcam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getVideoTracks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; webcamState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;webcamState &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;startWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;stopWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;cardPhotoButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;videoWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardVideo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;videoHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Setup Canvas&lt;/span&gt;&lt;br /&gt;  cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Draw video&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cardVideo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Create frame image&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; frame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardFrame&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;crossOrigin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Ensure frame loaded&lt;/span&gt;&lt;br /&gt;  frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Draw frame to canvas&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Output final composed canvas to DOM img&lt;/span&gt;&lt;br /&gt;    cardImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cardCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;image/jpeg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;stopWebcam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  cardWebcamButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;holiday-card scripted&quot;&gt;
  &lt;video class=&quot;holiday-card__video&quot; autoplay=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;/video&gt;
  &lt;img class=&quot;holiday-card__img&quot; src=&quot;https://12daysofweb.dev/img/12DaysCardFrame.svg&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;
&lt;div class=&quot;holiday-card__actions scripted&quot;&gt;
  &lt;span id=&quot;holiday-webcam-instructions&quot;&gt;Webcam required to enable taking a photo for the holiday card&lt;/span&gt;
  &lt;button type=&quot;button&quot; class=&quot;holiday-card-webcam&quot; aria-describedby=&quot;holiday-webcam-instructions&quot; data-state=&quot;offline&quot;&gt;Start Webcam&lt;/button&gt;
  &lt;button type=&quot;button&quot; class=&quot;holiday-card-photo&quot; disabled=&quot;&quot;&gt;Take Photo&lt;/button&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const constraints = {
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 },
    facingMode: &quot;user&quot;
  }
};

const cardFrame = &quot;/img/12DaysCardFrame.svg&quot;;
// Scoped to prevent working on the CSS demo :)
const card = document.querySelector(&quot;.scripted.holiday-card&quot;);
const cardImage = document.querySelector(&quot;.scripted .holiday-card__img&quot;);
const cardVideo = document.querySelector(&quot;.scripted .holiday-card__video&quot;);
const cardWebcamButton = document.querySelector(&quot;.scripted .holiday-card-webcam&quot;);
const cardPhotoButton = document.querySelector(&quot;.scripted .holiday-card-photo&quot;);
const cardCanvas = document.createElement(&quot;canvas&quot;);

card.style.setProperty(&quot;--card-height&quot;, card.offsetWidth * 0.5625 + &quot;px&quot;);

const handleSuccess = (stream) =&gt; {
  cardWebcamButton.dataset.state = &quot;streaming&quot;;
  cardWebcamButton.textContent = &quot;Stop Webcam&quot;;
  cardImage.src = cardFrame;
  cardPhotoButton.removeAttribute(&quot;disabled&quot;);

  window.stream = stream;
  cardVideo.srcObject = stream;
};

const handleError = (error) =&gt; {
  console.error(&quot;Error: &quot;, error);
};

const startWebcam = () =&gt; {
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(handleSuccess)
    .catch(handleError);
};

const stopWebcam = () =&gt; {
  cardWebcamButton.dataset.state = &quot;offline&quot;;
  cardWebcamButton.textContent = &quot;Start Webcam&quot;;
  cardPhotoButton.setAttribute(&quot;disabled&quot;, &quot;disabled&quot;);

  if (window.stream) {
    window.stream.getVideoTracks()[0].stop();
  }
};

cardWebcamButton.addEventListener(&quot;click&quot;, (e) =&gt; {
  const webcamState = e.target.dataset.state;

  if (webcamState === &quot;offline&quot;) {
    startWebcam();
  } else {
    stopWebcam();
  }
});

cardPhotoButton.addEventListener(&quot;click&quot;, () =&gt; {
  const width = cardVideo.videoWidth;
  const height = cardVideo.videoHeight;

  // Setup Canvas
  cardCanvas.width = width;
  cardCanvas.height = height;
  const ctx = cardCanvas.getContext(&quot;2d&quot;);

  // Draw video
  ctx.drawImage(cardVideo, 0, 0);

  // Create frame image
  const frame = new Image(width, height);
  frame.src = cardFrame;
  frame.setAttribute(&quot;crossOrigin&quot;, &quot;anonymous&quot;);

  // Ensure frame loaded
  frame.onload = () =&gt; {
    // Draw frame to canvas
    ctx.drawImage(frame, 0, 0, width, height);
    // Output final composed canvas to DOM img
    cardImage.src = cardCanvas.toDataURL(&quot;image/jpeg&quot;, 1.0);
  };

  stopWebcam();
  cardWebcamButton.focus();
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;mobile-support&quot;&gt;Mobile support&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#mobile-support&quot; aria-labelledby=&quot;mobile-support&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Our generator is very likely to be functional on mobile given &lt;a href=&quot;https://caniuse.com/stream&quot; rel=&quot;noopener noreferrer&quot;&gt;support of the APIs in use&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;However, I noted that there&amp;#39;s a potential issue with setting the canvas size to match the video size. And that is that on mobile in portrait mode, our video will not receive a stream using the &lt;code&gt;16/9&lt;/code&gt; aspect ratio.&lt;/p&gt;&lt;p&gt;You may already be on a mobile device and have discovered how the camera stream in the preview has the portrait aspect ratio and is centered within the frame. This is thanks to CSS positioning the video element.&lt;/p&gt;&lt;p&gt;But, when you take a photo, a screenshot is successfully rendered but continues to have the portrait aspect ratio. This makes it look strange as the replaced still in our image element once again due to the CSS in place which causes it to falsely appear stretched. When you try to save it you&amp;#39;ll see that the actual photo is portrait dimensions but this causes the SVG to stretch. This isn&amp;#39;t completely terrible except that the demo SVG has text.&lt;/p&gt;&lt;p&gt;Consider this a challenge to you to work out how to resolve for mobile portrait mode! You could try to keep the portrait centered in the final image. Or, swap both the generator preview and the frame to accommodate a portrait orientation. Or whatever other solution makes sense to you!&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;ideas-for-expanding-the-generator&quot;&gt;Ideas for expanding the generator&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#ideas-for-expanding-the-generator&quot; aria-labelledby=&quot;ideas-for-expanding-the-generator&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Our holiday card generator is a solid base for building additional features for interacting with a user&amp;#39;s webcam.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create preset classes that apply CSS filters to the video to pass into the canvas as well&lt;/li&gt;&lt;li&gt;Provide a gallery of different frames to choose from, or different &amp;quot;stickers&amp;quot; or text phrases&lt;/li&gt;&lt;li&gt;Enhance the webcam script to allow the user to choose the video source or change the resolution&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you expand this idea or create something new with what you&amp;#39;ve learned, tag &lt;code&gt;#12DaysofWeb&lt;/code&gt; on Twitter or CodePen to let me know! I&amp;#39;d love to share your creations.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/capturing-user-media-streams/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Links to the APIs are included where discussed in the tutorial, and I definitely recommend reviewing the full array of options they provide.&lt;/p&gt;&lt;p&gt;Two tutorials I found very useful in researching how to create this generator:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.html5rocks.com/en/tutorials/getusermedia/intro/&quot; rel=&quot;noopener noreferrer&quot;&gt;Capture Audio and Video in HTML5&lt;/a&gt; has an interesting history towards the APIs we used today and several examples of other things that can be done that are sure to inspire you&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Taking_still_photos&quot; rel=&quot;noopener noreferrer&quot;&gt;Taking still photos with WebRTC on MDN&lt;/a&gt; covers similar things but in a more straightforward way&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For advanced techniques, &lt;a href=&quot;https://www.youtube.com/watch?v=1X-bXp_6XTI&quot; rel=&quot;noopener noreferrer&quot;&gt;learn to create webcam effects from Adam Kuhn&lt;/a&gt; in this recording. Or go deep on learning &lt;a href=&quot;https://developers.google.com/web/fundamentals/media/manipulating/live-effects&quot; rel=&quot;noopener noreferrer&quot;&gt;real-time effects for images and video&lt;/a&gt; with a little extra help from WebGL.&lt;/p&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>CSS Houdini Paint API</title>
    <link href="https://12daysofweb.dev/2021/houdini/"/>
    <updated>2021-12-17T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/houdini/</id>
    <content type="html">



&lt;p&gt;The CSS Houdini spec contains &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/Houdini#the_houdini_apis&quot; rel=&quot;noopener noreferrer&quot;&gt;a few different APIs&lt;/a&gt; but the currently &lt;a href=&quot;https://caniuse.com/css-paint-api&quot; rel=&quot;noopener noreferrer&quot;&gt;best-supported&lt;/a&gt; is the Paint API. Fortunately, there is a polyfill that allows the API to be used today, but it should still be considered a progressive enhancement.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s learn more about the Houdini Paint API and create our own worklet - the JavaScript class that contains our paint function.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-is-css-houdini&quot;&gt;What is CSS Houdini&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#what-is-css-houdini&quot; aria-labelledby=&quot;what-is-css-houdini&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Houdini APIs give you direct access to the CSS Object Model (CSSOM) which means you can provide custom instructions to the browser about how to render features not available in CSS. Since Houdini passes off your worklet function to the browser rendering engine, they are very performantly painted off the main thread.&lt;/p&gt;&lt;p&gt;Now, I could explain what&amp;#39;s possible with Houdini, but I recommend skipping over to &lt;a href=&quot;https://houdini.how/&quot; rel=&quot;noopener noreferrer&quot;&gt;Houdini.how&lt;/a&gt; for a few minutes to scroll through the examples. &lt;/p&gt;&lt;p&gt;Notice that &lt;code&gt;paint()&lt;/code&gt; function applied to things like &lt;code&gt;background&lt;/code&gt;, &lt;code&gt;background-image&lt;/code&gt;, &lt;code&gt;border-image&lt;/code&gt;, and &lt;code&gt;mask-image&lt;/code&gt;? That&amp;#39;s how the paint worklet is called. Additionally, a worklet can receive CSS custom properties which makes them flexible and customizable per implementation.&lt;/p&gt;&lt;p&gt;Houdini worklets are encouraged to be shared, and you may have also noticed how those demos included a CDN link and/or NPM link. An additional reason beyond sharing the worklets is that they must be run on a local server or over HTTPS.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;developing-a-css-houdini-paint-worklet&quot;&gt;Developing a CSS Houdini Paint worklet&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#developing-a-css-houdini-paint-worklet&quot; aria-labelledby=&quot;developing-a-css-houdini-paint-worklet&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Worklets are created as JavaScript classes. For a preview of the worklet we&amp;#39;re going to create, scroll to the bottom of the page! The &amp;quot;snow&amp;quot; effect is created via Houdini.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;worklet-environment-and-initial-setup&quot;&gt;Worklet environment and initial setup&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#worklet-environment-and-initial-setup&quot; aria-labelledby=&quot;worklet-environment-and-initial-setup&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;To create the worklet, I&amp;#39;ll assume you&amp;#39;re working on a local server. I prefer &lt;a href=&quot;https://11ty.rocks/posts/create-your-first-basic-11ty-website/&quot; rel=&quot;noopener noreferrer&quot;&gt;Eleventy&lt;/a&gt; to quickly get this up and running, but any setup that can run a local server such as through Browsersync will do.&lt;/p&gt;&lt;p&gt;For the simplest starting point, create:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;worklet.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;style.css&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In your HTML file, we won&amp;#39;t link to the worklet like a normal script. Instead, we&amp;#39;ll call it with a special function to make it available to the browser and our styles:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- added in index.html --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paintWorklet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paintWorklet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;worklet.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Earlier I mentioned there was a polyfill, which you&amp;#39;ll need for support currently in Firefox and Safari. As the simplest way to include that, you can link to it prior to including your worklet from the unpkg CDN:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/css-paint-polyfill&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;While in your HTML file, let&amp;#39;s add a simple &lt;code&gt;div&lt;/code&gt; that we&amp;#39;ll attach the worklet to for testing. There seem to be some issues with trying to attach a worklet to the body unless you will not pass it custom properties. This element can certainly contain other content, it does not need to be reserved to work as a worklet target.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;snow&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we&amp;#39;ll add just a touch of style to our document so that our snow container has dimensions. We&amp;#39;ll also set a background color because that will not be provided as part of our worklet.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.snow&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;initialize-the-worklet-class&quot;&gt;Initialize the worklet class&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#initialize-the-worklet-class&quot; aria-labelledby=&quot;initialize-the-worklet-class&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Now in our worklet file, we&amp;#39;ll begin by defining what we want to call our worklet, which we&amp;#39;ll also use to prefix the related custom properties.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// worklet.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;houdini-snow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Following that, we&amp;#39;ll begin our class and include the initial call to &lt;code&gt;paint&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HoudiniSnow&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;registerPaint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HoudiniSnow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The class name is up to you, but notice it is also passed into the &lt;code&gt;registerPaint&lt;/code&gt; function.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;select-and-access-worklet-custom-properties&quot;&gt;Select and access worklet custom properties&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#select-and-access-worklet-custom-properties&quot; aria-labelledby=&quot;select-and-access-worklet-custom-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;At this point, it&amp;#39;s good to consider what custom properties - if any - we&amp;#39;d like to provide for customization. For this worklet, I decided on the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;--houdini-snow-min&lt;/code&gt; - minimum snowflake size, an integer that resolves to pixels&lt;/li&gt;&lt;li&gt;&lt;code&gt;--houdini-snow-max&lt;/code&gt; - maximum snowflake size, an integer that resolves to pixels&lt;/li&gt;&lt;li&gt;&lt;code&gt;--houdini-snow-fill&lt;/code&gt; - a string to select where to fill the element with snowflakes&lt;/li&gt;&lt;li&gt;&lt;code&gt;--houdini-snow-flakes&lt;/code&gt; - an integer corresponding to the total number of snowflakes&lt;/li&gt;&lt;/ul&gt;&lt;aside role=&quot;note&quot;&gt;&lt;p&gt;Unfamilar with or need a refresher on CSS custom properties? &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/&quot;&gt;Go back to Day 3!&lt;/a&gt;&lt;/p&gt;&lt;/aside&gt;&lt;p&gt;In order to access those properties, we&amp;#39;ll use the method for &lt;code&gt;inputProperties()&lt;/code&gt;. Of note, this method can access all properties on the element, not just custom ones. Place this prior to the &lt;code&gt;paint()&lt;/code&gt; function within the class:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inputProperties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-min&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-max&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-fill&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-flakes&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we&amp;#39;re ready to begin painting, so let&amp;#39;s examine the properties we&amp;#39;ve setup:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ctx&lt;/code&gt; refers to the rendering context and is how we&amp;#39;ll &amp;quot;draw&amp;quot; output. Officially called &lt;code&gt;PaintRenderingContext2D&lt;/code&gt;, it provides access to a subset of the HTML Canvas API.&lt;/li&gt;&lt;li&gt;&lt;code&gt;size&lt;/code&gt; returns the width and height of the element the worklet is being painted to&lt;/li&gt;&lt;li&gt;&lt;code&gt;properties&lt;/code&gt; is where the custom properties we&amp;#39;re expecting from &lt;code&gt;inputProperties&lt;/code&gt; get passed into the paint function&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We&amp;#39;ll begin by pulling out the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; from size and also gathering the values from the custom properties. For those, we need to do a bit of extra processing depending on what type we&amp;#39;re expecting - integer or string. And, we set some defaults in case the properties are not set.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; min &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-min&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; max &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-max&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// fill: &quot;all&quot; | &quot;top&quot; | &quot;bottom&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fill &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; properties&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-fill&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; flakes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;WORKLET&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-flakes&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that for the &lt;code&gt;fill&lt;/code&gt; we&amp;#39;ll accept three possible strings: &lt;code&gt;all&lt;/code&gt; to cover the element, or either &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;bottom&lt;/code&gt; to only cover the chosen half.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;add-randomness-responsibly-with-a-prng&quot;&gt;Add randomness responsibly with a PRNG&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#add-randomness-responsibly-with-a-prng&quot; aria-labelledby=&quot;add-randomness-responsibly-with-a-prng&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;In order to place the snowflakes, which we&amp;#39;ll simply draw as circles, we need to create an array populated with &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates which is what the canvas requires. And to ensure they don&amp;#39;t all end up in the same place but are distributed across the available space, we need a way to introduce some randomness.&lt;/p&gt;&lt;p&gt;The key to remember here about the paint API is that repainting is triggered when anything causes the layout to change. For example, resizing the browser. Depending on your worklet, allowing randomized positioning on repaint can cause an unwanted motion effect or even flashing from the rapid repaints. And that can cause some users migraines or even seizures.&lt;/p&gt;&lt;p&gt;Clever mathematical-minded folks have figured out how to create what they call pseudorandom number generators (PRNG). These have the appearance of randomness, but the behavior is that given an input the function always returns the same output. I found out about this method &lt;a href=&quot;https://css-tricks.com/conjuring-generative-blobs-with-the-css-paint-api/&quot; rel=&quot;noopener noreferrer&quot;&gt;from George Francis&lt;/a&gt;, and I highly &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#additional-resources-and-worklet-ideas&quot;&gt;recommend their resources&lt;/a&gt; if you are interested in diving deep with the paint API and particularly generative art.&lt;/p&gt;&lt;p&gt;The PRNG that George recommends is &lt;code&gt;mulberry32&lt;/code&gt;, which looks quite scary but what it ultimately does is intake a &amp;quot;seed&amp;quot; number and returns a number between 0 and 1 for each request. So while those individual requests return a different number, as a group the returned numbers are the same so the output ultimately has the appearance of being the same.&lt;/p&gt;&lt;p&gt;This function may be placed outside of the class.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mulberry32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    a &lt;span class=&quot;token operator&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x6d2b79f5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;imul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;imul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4294967296&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We will use the number of flakes as the seed, and create the &lt;code&gt;random&lt;/code&gt; variable within our paint function:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; random &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mulberry32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flakes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;create-an-array-of-snowflake-coordinates&quot;&gt;Create an array of snowflake coordinates&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#create-an-array-of-snowflake-coordinates&quot; aria-labelledby=&quot;create-an-array-of-snowflake-coordinates&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;So now we have a way to attach randomness, but we also need to work out how to select a value between a minimum and maximum. This will be used to select &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; points but also to size the snowflake circles.&lt;/p&gt;&lt;p&gt;Once again, George helps point us to the answer here which is a lerp (linear interpolation) function. Given a start, end, and amount value (a number between 0 and 1 aka our random number), it will return a point between the start and end.&lt;/p&gt;&lt;p&gt;We&amp;#39;ll set up our &lt;code&gt;lerp&lt;/code&gt; function next to the &lt;code&gt;mulberry32&lt;/code&gt; one. When we want to fill the lower half, we have to make an adjustment to ensure it picks a point within the higher range, and it was necessary to pass a fourth optional parameter.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fill &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; end &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; amt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;end &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; amt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The easy coordinate is &lt;code&gt;x&lt;/code&gt; which will always be plotted between 0 and the width of the element. Given this idea of &amp;quot;top&amp;quot; and &amp;quot;bottom&amp;quot; half, the coordinate this affects is &lt;code&gt;y&lt;/code&gt; which will move the snowflake up or down within the element. So before we finally calculate the coordinates, we&amp;#39;ll prepare variables to adjust the &lt;code&gt;y&lt;/code&gt; range start and end.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fill &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bottom&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; endPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fill &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;top&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; heignt &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we have all the setup to create an array to hold each snowflakes coordinates:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; snowflakeArr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flakes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;startPos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; endPos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fill&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;draw-the-snowflakes-within-the-rendering-context&quot;&gt;Draw the snowflakes within the rendering context&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#draw-the-snowflakes-within-the-rendering-context&quot; aria-labelledby=&quot;draw-the-snowflakes-within-the-rendering-context&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;If you&amp;#39;ve made it this far, you&amp;#39;re about to be rewarded with finally painting the snowflakes!&lt;/p&gt;&lt;p&gt;Finally, it&amp;#39;s time to tap into the rendering context via our &lt;code&gt;ctx&lt;/code&gt; parameter and draw the snowflake circles. We&amp;#39;ll loop through our &lt;code&gt;snowflakeArr&lt;/code&gt; and for each snowflake do the following:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Generate the fill color using &lt;code&gt;hsla&lt;/code&gt; to produce a white color that has a randomized alpha with the help of another call to &lt;code&gt;lerp&lt;/code&gt; and the PRNG&lt;/li&gt;&lt;li&gt;Begin drawing the path, a crucial step for making a shape&lt;/li&gt;&lt;li&gt;Use the &lt;code&gt;arc&lt;/code&gt; function to draw the circle, once again with the help of &lt;code&gt;lerp&lt;/code&gt; and the PRNG to add variance to the snowflake circle size&lt;/li&gt;&lt;li&gt;Add the fill color so that the snowflake circle is visible&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;snowflakeArr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;hsla(0 0% 100% / &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;arc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And with that, our &lt;code&gt;houdini-snow&lt;/code&gt; worklet is complete.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;demo-of-the-houdini-snow-worklet&quot;&gt;Demo of the houdini-snow worklet&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#demo-of-the-houdini-snow-worklet&quot; aria-labelledby=&quot;demo-of-the-houdini-snow-worklet&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Try out changing the provided custom properties for this demo in dev tools to see how they affect the rendering of our &lt;code&gt;houdini-snow&lt;/code&gt; worklet.&lt;/p&gt;
    

    
    &lt;style&gt;
    .houdini-snow {
  --houdini-snow-min: 4;
  --houdini-snow-max: 8;
  --houdini-snow-fill: top;
  --houdini-snow-flakes: 400;

  background-color: lightblue;
  height: 30vh;
  background-image: paint(houdini-snow);
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;houdini-snow worklet sandbox&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.houdini-snow&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--houdini-snow-min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--houdini-snow-max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--houdini-snow-fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--houdini-snow-flakes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;houdini-snow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;houdini-snow&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-the-polyfill-and-providing-fallback-styles&quot;&gt;Using the polyfill and providing fallback styles&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#using-the-polyfill-and-providing-fallback-styles&quot; aria-labelledby=&quot;using-the-polyfill-and-providing-fallback-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;While we already included the link to the polyfill earlier, there&amp;#39;s an issue that can arise where it needs a little extra nudge to work after the page loads. We can use &lt;code&gt;setTimeout&lt;/code&gt; to trigger a repaint on elements that should be rendering a worklet by calling &lt;code&gt;window.getComputedStyle()&lt;/code&gt; against each element.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; snow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.snow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As with anything, be sure to test in Firefox and Safari to ensure the rendering meets your expectations.&lt;/p&gt;&lt;p&gt;The polyfill does not seem to support rendering within pseudo-elements which can be a significant limitation if you are making your worklet a focal point. You may need to fall back to background images or other solutions, which you can accomplish using CSS &lt;code&gt;@supports&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;worklet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* fall back styles here */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources-and-worklet-ideas&quot;&gt;Additional resources and worklet ideas&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/houdini/#additional-resources-and-worklet-ideas&quot; aria-labelledby=&quot;additional-resources-and-worklet-ideas&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;For an overview of additional features available in the Paint API, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API/Guide&quot; rel=&quot;noopener noreferrer&quot;&gt;review the guide from MDN&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I&amp;#39;ve mentioned George Francis and if you are interested in the Houdini Paint API and/or generative art, definitely check out their other resources, including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/conjuring-generative-blobs-with-the-css-paint-api/&quot; rel=&quot;noopener noreferrer&quot;&gt;Conjuring Generative Blobs&lt;/a&gt; which also shows how to use the produced shape as a mask&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/creating-generative-patterns-with-the-css-paint-api/&quot; rel=&quot;noopener noreferrer&quot;&gt;Creating Generative Patterns&lt;/a&gt; reviews how to create many types of shapes and several spacing and layout methods&lt;/li&gt;&lt;li&gt;Watch George explain &lt;a href=&quot;https://www.youtube.com/watch?v=31QxKFJ7bOA&quot; rel=&quot;noopener noreferrer&quot;&gt;creating generative design with Houdini&lt;/a&gt; at LondonCSS&lt;/li&gt;&lt;li&gt;Get inspired by reviewing &lt;a href=&quot;https://codepen.io/georgedoescode/pens/tags/?selected_tag=houdini&quot; rel=&quot;noopener noreferrer&quot;&gt;George&amp;#39;s Houdini worklets on CodePen&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Over on CSS-Tricks, Temani Afif has done a series of ideas, starting with this one on &lt;a href=&quot;https://css-tricks.com/exploring-the-css-paint-api-image-fragmentation-effect/&quot; rel=&quot;noopener noreferrer&quot;&gt;image fragmentation effects&lt;/a&gt; (motion warning).&lt;/p&gt;&lt;p&gt;Jumpstart your worklet environment including getting it ready to publish on npm by using my &lt;a href=&quot;https://github.com/5t3ph/11ty-css-houdini&quot; rel=&quot;noopener noreferrer&quot;&gt;Eleventy-based worklet starter.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Don&amp;#39;t forget to check out the &lt;a href=&quot;https://houdini.how/resources&quot; rel=&quot;noopener noreferrer&quot;&gt;resources available on Houdini.how&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Have fun painting!&lt;/p&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Audio API</title>
    <link href="https://12daysofweb.dev/2021/audio-api/"/>
    <updated>2021-12-16T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/audio-api/</id>
    <content type="html">



&lt;p&gt;While you&amp;#39;re not likely to be embedding audio on the web every day, you never know when it might be useful! &lt;/p&gt;&lt;p&gt;The API is vast, and complements the &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; native HTML element. We&amp;#39;ll review the element first, then look at a few parts of the API to build a simple custom player.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;the-audio-html-element&quot;&gt;The audio HTML element&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#the-audio-html-element&quot; aria-labelledby=&quot;the-audio-html-element&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; HTML element allows you to embed audio anywhere, and adding the &lt;code&gt;controls&lt;/code&gt; attribute also displays the browser&amp;#39;s audio player.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&amp;lt;audio controls src=&lt;span class=&quot;token string&quot;&gt;&quot;jingle-bells.mp3&quot;&lt;/span&gt;&gt;&amp;lt;/audio&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The results of that HTML will display a little differently depending on your browser.&lt;/p&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;figure style=&quot;padding: 1rem; border: 1px dashed;&quot;&gt;
  &lt;audio controls=&quot;&quot; src=&quot;https://12daysofwebdev.cdn.prismic.io/12daysofwebdev/b60d021d-413b-45db-a561-e5f7b57cfc89_jingle-bells.mp3&quot;&gt;&lt;/audio&gt;
&lt;figcaption&gt;&lt;small&gt;Audio converted and edited from the &lt;a href=&quot;https://www.westnet.com/Holiday/midi/&quot; target=&quot;_blank&quot;&gt;Jingle Bells midi&lt;/a&gt;.&lt;/small&gt;&lt;/figcaption&gt;&lt;/figure&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attributes&quot; rel=&quot;noopener noreferrer&quot;&gt;Additional available attributes&lt;/a&gt; outside of controls include &lt;code&gt;autoplay&lt;/code&gt;, &lt;code&gt;loop&lt;/code&gt;, and &lt;code&gt;muted&lt;/code&gt;. You can also include &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements as child elements of &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; instead of using the &lt;code&gt;src&lt;/code&gt; attribute.&lt;/p&gt;&lt;p&gt;You may also define what, if anything, to preload, where the default is different per browser. The option selected for preloading depends on how you intend to use the audio element Options include none, metadata, and auto.&lt;/p&gt;
    

    

    

    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-custom-audio-player&quot;&gt;Creating a custom audio player&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#creating-a-custom-audio-player&quot; aria-labelledby=&quot;creating-a-custom-audio-player&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The primary issue with the native player is that there is no cross-browser styling control over its elements. And each browser player is also inconsistent in which controls they provide.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Chromium&lt;/strong&gt;: play/pause, duration and time elapsed, timeline scrubber, volume, and additional menu to download or select playback speed&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Firefox&lt;/strong&gt;: play/pause, duration and time elapsed, timeline scrubber, and volume&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Safari&lt;/strong&gt;: play/pause, timeline scrubber, and time elapsed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For our custom player, we&amp;#39;re using a reduced scope since this is intended as an introduction to this API. There are certainly more features you could add, but we&amp;#39;ll focus on:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Displaying track title (static)&lt;/li&gt;&lt;li&gt;Duration and time elapsed&lt;/li&gt;&lt;li&gt;Play/pause state toggle&lt;/li&gt;&lt;li&gt;Mute/unmute state toggle&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;audio-player-html&quot;&gt;Audio player HTML&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#audio-player-html&quot; aria-labelledby=&quot;audio-player-html&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;First, we&amp;#39;ll build out semantic, accessible HTML for our custom audio player. I encourage always starting with this step (yes, even if you&amp;#39;re using a framework).&lt;/p&gt;&lt;p&gt;We&amp;#39;ll create a container with the &lt;code&gt;role&lt;/code&gt; of &amp;quot;group&amp;quot; to help define the boundaries of our custom player for assistive technology (AT), as well as an &lt;code&gt;aria-label&lt;/code&gt; to label the group &amp;quot;Audio player&amp;quot;. And, we&amp;#39;ll go ahead and add an &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; element as the first child. Note that we&amp;#39;re specifically defining the &lt;code&gt;preload&lt;/code&gt; here since we are planning to use the metadata for display.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Audio player&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;audio&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;preload&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;jingle-bells.mp3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;audio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since we haven&amp;#39;t added the &lt;code&gt;controls&lt;/code&gt; attribute, browsers will default to hiding the audio element.&lt;/p&gt;&lt;p&gt;Next, we&amp;#39;ll use a headline element to label what is currently playing:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__current&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Playing:&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Jingle Bells&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Following that, we&amp;#39;ll add two button elements to use as our player toggles for play and mute actions. We&amp;#39;re wrapping the text in a span which we&amp;#39;ll accessibly hide so that it is used for the label by AT. The icon &lt;code&gt;svg&lt;/code&gt; include &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; since they are decorative as far as AT is concerned given the accessible labeling text.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;play&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-state&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;paused&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Play&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-play&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M8 5v14l11-7z&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-pause&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hidden&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M6 19h4V5H6v14zm8-14v14h4V5h-4z&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mute&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-pressed&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Mute&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- svg path --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are two SVG icons for a &amp;quot;play&amp;quot; and &amp;quot;pause&amp;quot; icon, where the &amp;quot;pause&amp;quot; initially has the &lt;code&gt;hidden&lt;/code&gt; attribute so that it is not displayed. We&amp;#39;ll toggle the icons&amp;#39; &lt;code&gt;hidden&lt;/code&gt; attribute as well as the label content when it is selected.&lt;/p&gt;&lt;p&gt;The other important attributes on the buttons are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;data-action&lt;/code&gt;: used for finding the element in JS. We&amp;#39;re avoiding an ID in case of multiple audio players and avoiding a class to discourage removing or changing the name&lt;/li&gt;&lt;li&gt;&lt;code&gt;aria-pressed&lt;/code&gt;: identifies the mute button as a toggle button for AT and will convey the changed state which will update dynamically in JS&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Finally, we&amp;#39;ll use a paragraph to contain the time information and set default zero values. Here again, we&amp;#39;re preparing our markup to hide the AT labels, so the final visual will be &lt;code&gt;0:00 / 0:00&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__time&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Elapsed time&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;nbsp;&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-time&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;remaining&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;0:00&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; / &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;audio-player__label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Total time&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;nbsp;&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-time&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;total&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;0:00&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;audio-player-styles&quot;&gt;Audio player styles&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#audio-player-styles&quot; aria-labelledby=&quot;audio-player-styles&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Since our audio player is completely made of custom elements now, we have full styling control. We&amp;#39;ll be leveraging CSS grid to arrange the elements.&lt;/p&gt;&lt;p&gt;You can expand the styles to review them fully, and lookout for a few key features:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We hide our labels using the styles from &lt;a href=&quot;https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html#hiding-content-visually&quot; rel=&quot;noopener noreferrer&quot;&gt;Scott O&amp;#39;Hara&amp;#39;s visually hidden class&lt;/a&gt;&lt;/li&gt;&lt;li&gt;On the &lt;code&gt;.audio-player&lt;/code&gt; container, we set &lt;code&gt;width&lt;/code&gt; using &lt;code&gt;fit-content&lt;/code&gt; which visually shrinks the player to its intrinsic width where supported&lt;/li&gt;&lt;li&gt;For the toggle buttons SVG, we set &lt;code&gt;pointer-events: none&lt;/code&gt; so that the click event &amp;quot;falls through&amp;quot; to the button element&lt;/li&gt;&lt;li&gt;The time content has set &lt;code&gt;font-variant-numeric: tabular-nums&lt;/code&gt; which, when supported by the font, requests that numeric values take on monospace behavior, which prevents our audio player&amp;#39;s width visibly adjusting when wider or narrower numbers are displayed&lt;/li&gt;&lt;/ul&gt;
    

    
    &lt;style&gt;
    .audio-player * {
  margin: 0;
}

.audio-player__label {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

.audio-player {
  padding: 1rem;
  background: #222;
  color: #fff;
  border-radius: 0.5rem;
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  width: fit-content;
  gap: 1rem;
}

.audio-player__current {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.25em;
  font-size: 1.25rem;
  font-weight: bold;
}

.audio-player__current small {
  font-weight: normal;
  text-transform: uppercase;
}

.audio-player__button {
  all: unset;
  cursor: pointer;
  display: inline-grid;
  place-content: center;
  border-radius: 0.25rem;
  border: 2px solid #fff;
  padding: 0.15em;
}

.audio-player__button:focus {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.audio-player__button svg {
  fill: currentcolor;
  pointer-events: none;
}

.audio-player__button[aria-pressed=true],
.audio-player__button[data-state=playing] {
  background-color: #fff;
  color: #222;
}

.audio-player__time {
  font-variant-numeric: tabular-nums;
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Audio player CSS&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__label&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0 0 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;white-space&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nowrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto auto 1fr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fit-content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__current&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-column&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1 / -1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__current small&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uppercase&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.15em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__button:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__button svg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; currentcolor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;pointer-events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__button[aria-pressed=true],&lt;br /&gt;.audio-player__button[data-state=playing]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.audio-player__time&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-variant-numeric&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tabular-nums&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div role=&quot;group&quot; aria-label=&quot;Audio player&quot; class=&quot;audio-player&quot;&gt;
  &lt;h3 class=&quot;audio-player__current&quot;&gt;&lt;small&gt;Playing:&lt;/small&gt; Jingle Bells&lt;/h3&gt;
  &lt;button data-action=&quot;play&quot; data-state=&quot;paused&quot; class=&quot;audio-player__button&quot; type=&quot;button&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Play&lt;/span&gt;
    &lt;svg data-play=&quot;&quot; height=&quot;24&quot; width=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;
      &lt;path d=&quot;M8 5v14l11-7z&quot;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;svg data-pause=&quot;&quot; hidden=&quot;&quot; height=&quot;24&quot; width=&quot;24&quot;&gt;&lt;path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;
  &lt;/button&gt;
  &lt;button data-action=&quot;mute&quot; class=&quot;audio-player__button&quot; type=&quot;button&quot; aria-pressed=&quot;false&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Mute&lt;/span&gt;
    &lt;svg height=&quot;24&quot; width=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;
      &lt;path d=&quot;M16.5 12A4.5 4.5 0 0 0 14 7.97v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51A8.796 8.796 0 0 0 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3 3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06a8.99 8.99 0 0 0 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4 9.91 6.09 12 8.18V4z&quot;&gt;&lt;/path&gt;
    &lt;/svg&gt;&lt;/button&gt;
  &lt;p class=&quot;audio-player__time&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Elapsed time&amp;nbsp;&lt;/span&gt;&lt;span data-time=&quot;remaining&quot;&gt;0:00&lt;/span&gt; / &lt;span class=&quot;audio-player__label&quot;&gt; Total time&amp;nbsp;&lt;/span&gt;&lt;span data-time=&quot;total&quot;&gt;0:00&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;audio-player-api-events&quot;&gt;Audio player API events&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#audio-player-api-events&quot; aria-labelledby=&quot;audio-player-api-events&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Both the audio and video API inherit &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement&quot; rel=&quot;noopener noreferrer&quot;&gt;the HTMLMediaElement interface&lt;/a&gt;. There are many properties, methods, and events that you can use. We&amp;#39;ll hone in on some of the most essential for our simple player.&lt;/p&gt;&lt;p&gt;The capabilities we need for our audio player:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Toggle the aria-pressed state for the play and mute action buttons&lt;/li&gt;&lt;li&gt;Toggle play state&lt;/li&gt;&lt;li&gt;Toggle mute state&lt;/li&gt;&lt;li&gt;Set the total duration&lt;/li&gt;&lt;li&gt;Update the elapsed timestamp during playback&lt;/li&gt;&lt;li&gt;Reset the elapsed timestamp and play toggle state when the audio ends&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;First, we&amp;#39;ll find each element, including the &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; since we directly respond to events and set properties on it.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioElement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.audio-player audio&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioPlay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;play&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playLabel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.audio-player__label&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-play]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pauseIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-pause]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioMute &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-action=&quot;mute&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioTimeRemaining &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-time=&quot;remaining&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioTimeTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-time=&quot;total&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our play button functionality is the most complex. For setting play versus pause, we call those functions against the audio element. Additionally, we update the &lt;code&gt;data-state&lt;/code&gt; which is tied to styles, as well as change the text content of the label. Last, we use the handle &lt;code&gt;toggleAttribute&lt;/code&gt; JS function to toggle the &lt;code&gt;hidden&lt;/code&gt; attribute of the icons to efficiently flip their visibility.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isPlaying &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;playing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isPlaying&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;playing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pause&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  playIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  pauseIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For mute, we toggle the boolean &lt;code&gt;muted&lt;/code&gt; property and &lt;code&gt;aria-pressed&lt;/code&gt; state.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isMuted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-pressed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-pressed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isMuted&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;muted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isMuted&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that the toggles are working, it&amp;#39;s time to handle the time updates. There are three events we&amp;#39;ll listen to:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;loadedmetadata&lt;/code&gt;: allows us to confidently set the total time by getting the duration&lt;/li&gt;&lt;li&gt;&lt;code&gt;timeupdate&lt;/code&gt;: fires during playback and we&amp;#39;ll use it to update the elapsed time&lt;/li&gt;&lt;li&gt;&lt;code&gt;ended&lt;/code&gt;: signals the audio file has completed playback which we&amp;#39;ll use to reset the player state&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Since the time is calculated in seconds, we&amp;#39;ll first create a function to format it to &lt;code&gt;mm:ss&lt;/code&gt; for display&lt;code&gt;.&lt;/code&gt;&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;formatAudioTime&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNaN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; secondValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;secondValue &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    secondValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; secondValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; secondValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, we&amp;#39;ll call the formatting function for setting the total time upon the &lt;code&gt;loadedmetadata&lt;/code&gt; event and setting the time remaining on the &lt;code&gt;timeupdate&lt;/code&gt; event.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;loadedmetadata&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioTimeTotal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;formatAudioTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;duration&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timeupdate&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioTimeRemaining&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;formatAudioTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, we&amp;#39;ll complete our player by resetting the play button state and remaining time upon the &lt;code&gt;ended&lt;/code&gt; event.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ended&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  playIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  pauseIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  audioTimeRemaining&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following is our final demo as well as the complete script.&lt;/p&gt;
    

    

    
    &lt;details&gt;
    &lt;summary&gt;Audio player JS&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .playable scoping due to previous CSS demo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ⚡️ Challenge: Adapt this to work for multiple players per page&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioElement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.playable.audio-player audio&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioPlay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.playable [data-action=&quot;play&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playLabel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.audio-player__label&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-play]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pauseIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-pause]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioMute &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.playable [data-action=&quot;mute&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioTimeRemaining &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.playable [data-time=&quot;remaining&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; audioTimeTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.playable [data-time=&quot;total&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isPlaying &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;playing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isPlaying&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;playing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pause&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  playIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  pauseIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isMuted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-pressed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  audioMute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-pressed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isMuted&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;muted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isMuted&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;formatAudioTime&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNaN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; secondValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;secondValue &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    secondValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; secondValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; minuteValue &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; secondValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;loadedmetadata&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioTimeTotal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;formatAudioTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;duration&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timeupdate&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioTimeRemaining&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;formatAudioTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;audioElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ended&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  audioPlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;paused&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  playLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Play&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  playIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  pauseIcon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggleAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  audioTimeRemaining&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div role=&quot;group&quot; aria-label=&quot;Audio player&quot; class=&quot;audio-player playable&quot;&gt;
  &lt;audio preload=&quot;metadata&quot; src=&quot;https://12daysofwebdev.cdn.prismic.io/12daysofwebdev/b60d021d-413b-45db-a561-e5f7b57cfc89_jingle-bells.mp3&quot;&gt;&lt;/audio&gt;
  &lt;h3 class=&quot;audio-player__current&quot;&gt;&lt;small&gt;Playing:&lt;/small&gt; Jingle Bells&lt;/h3&gt;
  &lt;button data-action=&quot;play&quot; class=&quot;audio-player__button&quot; type=&quot;button&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Play&lt;/span&gt;&lt;svg data-play=&quot;&quot; height=&quot;24&quot; width=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;
      &lt;path d=&quot;M8 5v14l11-7z&quot;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;svg data-pause=&quot;&quot; hidden=&quot;&quot; height=&quot;24&quot; width=&quot;24&quot;&gt;&lt;path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;
  &lt;button data-action=&quot;mute&quot; class=&quot;audio-player__button&quot; type=&quot;button&quot; aria-pressed=&quot;false&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Mute&lt;/span&gt;
    &lt;svg height=&quot;24&quot; width=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;
      &lt;path d=&quot;M16.5 12A4.5 4.5 0 0 0 14 7.97v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51A8.796 8.796 0 0 0 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3 3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06a8.99 8.99 0 0 0 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4 9.91 6.09 12 8.18V4z&quot;&gt;&lt;/path&gt;
    &lt;/svg&gt;&lt;/button&gt;
  &lt;p class=&quot;audio-player__time&quot;&gt;&lt;span class=&quot;audio-player__label&quot;&gt;Elapsed time&amp;nbsp;&lt;/span&gt;&lt;span data-time=&quot;remaining&quot;&gt;0:00&lt;/span&gt; / &lt;span class=&quot;audio-player__label&quot;&gt; Total time&amp;nbsp;&lt;/span&gt;&lt;span data-time=&quot;total&quot;&gt;0:00&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    // .playable scoping due to previous CSS demo
// ⚡️ Challenge: Adapt this to work for multiple players per page
const audioElement = document.querySelector(&quot;.playable.audio-player audio&quot;);
const audioPlay = document.querySelector(&#39;.playable [data-action=&quot;play&quot;]&#39;);
const playLabel = audioPlay.querySelector(&#39;.audio-player__label&#39;);
const playIcon = audioPlay.querySelector(&#39;[data-play]&#39;);
const pauseIcon = audioPlay.querySelector(&#39;[data-pause]&#39;);
const audioMute = document.querySelector(&#39;.playable [data-action=&quot;mute&quot;]&#39;);
const audioTimeRemaining = document.querySelector(&#39;.playable [data-time=&quot;remaining&quot;]&#39;);
const audioTimeTotal = document.querySelector(&#39;.playable [data-time=&quot;total&quot;]&#39;);

audioPlay.addEventListener(&quot;click&quot;, (e) =&gt; {
  const isPlaying = audioPlay.dataset.state === &quot;playing&quot;;

  if (isPlaying) {
    audioElement.pause();
    audioPlay.dataset.state = &#39;paused&#39;;
    playLabel.textContent = &quot;Play&quot;;
  } else {
    audioElement.play();
    audioPlay.dataset.state = &#39;playing&#39;;
    playLabel.textContent = &quot;Pause&quot;;
  }
  
  playIcon.toggleAttribute(&#39;hidden&#39;);
  pauseIcon.toggleAttribute(&#39;hidden&#39;);
});

audioMute.addEventListener(&quot;click&quot;, (e) =&gt; {
  const isMuted = audioMute.getAttribute(&quot;aria-pressed&quot;) === &quot;true&quot;;

  audioMute.setAttribute(&quot;aria-pressed&quot;, !isMuted);
  audioElement.muted = !isMuted;
});

const formatAudioTime = (time) =&gt; {
  if (isNaN(time)) return;

  const minuteValue = Math.floor(time / 60);
  let secondValue = Math.floor(time - minuteValue * 60);

  if (secondValue &lt; 10) {
    secondValue = &quot;0&quot; + secondValue;
  }

  return minuteValue + &quot;:&quot; + secondValue;
};

audioElement.addEventListener( &quot;loadedmetadata&quot;, () =&gt; 
  (audioTimeTotal.textContent = formatAudioTime(audioElement.duration))
);

audioElement.addEventListener( &quot;timeupdate&quot;, () =&gt; 
  (audioTimeRemaining.textContent = formatAudioTime(audioElement.currentTime))
);

audioElement.addEventListener(&quot;ended&quot;, () =&gt; {
  audioPlay.dataset.state = &#39;paused&#39;;
  playLabel.textContent = &quot;Play&quot;;
  playIcon.toggleAttribute(&#39;hidden&#39;);
  pauseIcon.toggleAttribute(&#39;hidden&#39;);
  audioTimeRemaining.textContent = &quot;0:00&quot;;
});
    &lt;/script&gt;
    

    
  

  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;ideas-for-using-the-audio-api&quot;&gt;Ideas for using the audio API&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#ideas-for-using-the-audio-api&quot; aria-labelledby=&quot;ideas-for-using-the-audio-api&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Audio elements with no controls can be used to help respond to &lt;code&gt;play()&lt;/code&gt; commands to add fun audio enhancements. &lt;a href=&quot;https://jason.af/&quot; rel=&quot;noopener noreferrer&quot;&gt;Click Jason&amp;#39;s head for inspiration&lt;/a&gt;. Be sure to also provide the user a toggle to turn off all sounds.&lt;/li&gt;&lt;li&gt;Create a more full-featured player including &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Visualizations_with_Web_Audio_API&quot; rel=&quot;noopener noreferrer&quot;&gt;visualizations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Use the API to aid animation like Andrew Rubin does to &lt;a href=&quot;https://frontend.horse/episode/animating-svg-music-gsap&quot; rel=&quot;noopener noreferrer&quot;&gt;animate a cartoon band&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Have a podcast? Now you can create a custom player embed!&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/audio-api/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Learn with Jason from Lindsey Kopacz to &lt;a href=&quot;https://www.learnwithjason.dev/build-a-custom-accessible-audio-player&quot; rel=&quot;noopener noreferrer&quot;&gt;create an accessible audio player&lt;/a&gt;&lt;/li&gt;&lt;li&gt;MDN has a large section with many &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API&quot; rel=&quot;noopener noreferrer&quot;&gt;guides to explore the audio API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Check out what all is available for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement&quot; rel=&quot;noopener noreferrer&quot;&gt;HTMLMediaElement&lt;/a&gt; (which applies to video, too)&lt;/li&gt;&lt;li&gt;If you&amp;#39;re wondering why we didn&amp;#39;t use &lt;code&gt;aria-pressed&lt;/code&gt; for the play button, learn from Sarah Higley about &lt;a href=&quot;https://sarahmhigley.com/writing/playing-with-state/&quot; rel=&quot;noopener noreferrer&quot;&gt;conveying the state of toggle buttons&lt;/a&gt; to AT&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>CSS Custom Properties</title>
    <link href="https://12daysofweb.dev/2021/css-custom-properties/"/>
    <updated>2021-12-15T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/css-custom-properties/</id>
    <content type="html">



&lt;p&gt;CSS custom properties are &lt;a href=&quot;https://caniuse.com/css-variables&quot; rel=&quot;noopener noreferrer&quot;&gt;very well supported&lt;/a&gt; and are absolutely something to make a priority to learn and use in 2022.&lt;/p&gt;&lt;p&gt;There are many things to love about custom properties, and we&amp;#39;ll overview the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#what-are-css-custom-properties&quot;&gt;What are CSS custom properties&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#how-custom-properties-differ-from-preprocessor-variables&quot;&gt;How they&amp;#39;re different from preprocessor variables&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#why-should-i-use-css-custom-properties&quot;&gt;Why you should use custom properties&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#using-custom-properties-to-set-defaults&quot;&gt;Using them to set defaults&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#custom-properties-and-inheritance&quot;&gt;Custom properties and inheritance&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#accessing-and-setting-custom-properties-with-javascript&quot;&gt;Accessing and setting custom properties with JavaScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-are-css-custom-properties&quot;&gt;What are CSS custom properties?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#what-are-css-custom-properties&quot; aria-labelledby=&quot;what-are-css-custom-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Custom properties allow you to define variables for re-use in your styles. Just like other CSS properties, they abide by the rules of the cascade. This is a great feature because it means we can define them with defaults and then provide overrides as needed. If you&amp;#39;re a JS dev, think of them as equivalent to being defined with &lt;code&gt;let&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;To define a custom property, use the name of your choice preceded by two dashes, for example: &lt;code&gt;--my-property&lt;/code&gt;. Then you can use that value by calling it within the &lt;code&gt;var()&lt;/code&gt; CSS function in place of providing a standard value.&lt;/p&gt;&lt;p&gt;For this class, we&amp;#39;re defining a custom &lt;code&gt;--color&lt;/code&gt; property and then using it for the &lt;code&gt;color&lt;/code&gt; value:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;heading-wrapper h3&quot;&gt;
    &lt;h3 id=&quot;how-custom-properties-differ-from-preprocessor-variables&quot;&gt;How custom properties differ from preprocessor variables&lt;/h3&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#how-custom-properties-differ-from-preprocessor-variables&quot; aria-labelledby=&quot;how-custom-properties-differ-from-preprocessor-variables&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Preprocessors like Sass or LESS have had variables for many years. However, those variables are ultimately static once compiled into your final stylesheet. This is great for values that you repeat across your styles but don&amp;#39;t have a need to change post-compilation.&lt;/p&gt;&lt;p&gt;Custom properties have the advantage for values that may change dynamically client-side or contextually via inline style overrides. Additionally, using preprocessor variables to set a value such as our button color requires redefining all properties used in a modifier class to change to a different preprocessor variable. In other words, you can&amp;#39;t change the value of a preprocessor variable after it was defined, but you can do that with CSS custom properties (pending &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#custom-properties-and-inheritance&quot;&gt;cascade inheritance&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Another advantage for preprocessor variables over custom properties is defining strings to use anywhere, such as for media query breakpoints, or to even define a selector string which can look like the following:&lt;/p&gt;&lt;pre class=&quot;language-scss&quot;&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Example in Sass which allows overriding the $classes value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$classes&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.class-a, .class-b&quot;&lt;/span&gt; &lt;span class=&quot;token statement keyword&quot;&gt;!default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;#{$classes}&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// define properties for this rule&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;why-should-i-use-css-custom-properties&quot;&gt;Why should I use CSS custom properties?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#why-should-i-use-css-custom-properties&quot; aria-labelledby=&quot;why-should-i-use-css-custom-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s answer that by enhancing our previous code example for changing the &lt;code&gt;.btn&lt;/code&gt; color.&lt;/p&gt;&lt;p&gt;If I want to change the color of the button text and border on hover, I no longer need to repeat those properties. Instead, we can just change the &lt;code&gt;--color&lt;/code&gt; value.&lt;/p&gt;&lt;p&gt;Notice how we&amp;#39;re able to use the &lt;code&gt;var()&lt;/code&gt; function as only part of the value, in this case, to define the &lt;code&gt;border-color&lt;/code&gt;. This opens up endless opportunities for custom properties!&lt;/p&gt;
    

    
    &lt;style&gt;
    .btn {
  --color: blue;

  color: var(--color);
  border: 2px solid var(--color);
  padding: 0.25em 0.5em;
  border-radius: 0.25em;
  text-decoration: none;
}

.btn:hover {
  --color: red;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;CSS to update color variable for hover state&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em 0.5em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.btn:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;a href=&quot;javascript:;&quot; class=&quot;btn&quot;&gt;Hover or tap me!&lt;/a&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;using-custom-properties-to-set-defaults&quot;&gt;Using custom properties to set defaults&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#using-custom-properties-to-set-defaults&quot; aria-labelledby=&quot;using-custom-properties-to-set-defaults&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;A feature of &lt;code&gt;var()&lt;/code&gt; is the ability to both call a custom property, but also set a fallback which you can also think of as a default.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can even set the default using another custom property. Using that idea, let&amp;#39;s create a different version of our &lt;code&gt;.btn&lt;/code&gt; class to allow modifying the &lt;code&gt;--border-color&lt;/code&gt; while also setting the &lt;code&gt;--color&lt;/code&gt; variable as a default.&lt;/p&gt;
    

    
    &lt;style&gt;
    .btn-v2 {
  --color: blue;

  color: var(--color);
  border: 2px solid var(--border-color, var(--color));
  padding: 0.25em 0.5em;
  border-radius: 0.25em;
  text-decoration: none;
}

.btn-v2:hover {
  --border-color: red;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Combining local variables with defaults&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn-v2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--border-color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em 0.5em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.btn-v2:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;a href=&quot;javascript:;&quot; class=&quot;btn-v2&quot;&gt;Hover or tap me!&lt;/a&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;custom-properties-and-inheritance&quot;&gt;Custom properties and inheritance&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#custom-properties-and-inheritance&quot; aria-labelledby=&quot;custom-properties-and-inheritance&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;It&amp;#39;s important to learn a few things about how CSS custom properties are computed and inherited.&lt;/p&gt;&lt;p&gt;My own introduction into custom properties led me to believe that I should load them all on the &lt;code&gt;:root&lt;/code&gt; selector. Instead, it&amp;#39;s recommended to only hold truly global properties in the &lt;code&gt;:root&lt;/code&gt;, and more class or component-specific styles closer to where they are needed.&lt;/p&gt;&lt;p&gt;A key concept is that custom property values are computed once per element, and then the computed value is available for inheritance. When you use custom properties within &lt;code&gt;calc()&lt;/code&gt; or other values that need to be calculated, like the hue of &lt;code&gt;hsl()&lt;/code&gt;, then you are making the total computed value inheritable. You are not able to change a value within a calculation if it is set on an ancestor, as shown:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--size-lg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;3 * &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* this will not use the updated unit value for the calculation */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.margin-top-3xl&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--size-lg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One option to fix the previous inheritance issue is by using a combination of a base and modifier class so that the values are computed against the same element. In the demo, we&amp;#39;re still setting a global &lt;code&gt;--unit&lt;/code&gt; value and using it as the default on the base class.&lt;/p&gt;
    

    
    &lt;style&gt;
    :root {
  --unit: 10px;
}

.margin-top {
  --margin-unit: var(--unit);
  --multiplier: 1;

  margin-top: calc(var(--multiplier) * var(--margin-unit));
}

.margin-top--3xl {
  --margin-unit: 30px;
  --multiplier: 3;
}

div[class*=&quot;margin&quot;] {
  background-color: dodgerblue;
  color: white;
  padding: 0.5rem;
  font-size: 1.5rem;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Handling custom property inheritance&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.margin-top&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--margin-unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--multiplier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--multiplier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--margin-unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.margin-top--3xl&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--margin-unit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--multiplier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;div[class*=&quot;margin&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dodgerblue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div class=&quot;margin-top&quot;&gt;.margin-top&lt;/div&gt;

&lt;div class=&quot;margin-top margin-top--3xl&quot;&gt;.margin-top.margin-top--3xl&lt;/div&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;There are also times where it can be beneficial to use an undefined custom property, such as making utility classes even more flexible. The benefit of an undefined property is that it can inherit its value from any ancestor, which is excellent for updating values for a group of related elements.&lt;/p&gt;&lt;p&gt;Two options for using unset properties:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Completely undefined with no default, which means &lt;a href=&quot;https://www.w3.org/TR/css-variables-1/#invalid-variables&quot; rel=&quot;noopener noreferrer&quot;&gt;it will likely have the behavior of &lt;code&gt;unset&lt;/code&gt;&lt;/a&gt; for that property, for example: &lt;code&gt;color: var(--color)&lt;/code&gt; where &lt;code&gt;--color&lt;/code&gt; is not set within the rule&lt;/li&gt;&lt;li&gt;Undefined with a fallback to get the benefits of both inheritance and ensuring a default, example: &lt;code&gt;color: var(--color, blue)&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We used the second option in the &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#using-custom-properties-to-set-defaults&quot;&gt;demo around setting defaults&lt;/a&gt; to allow an optional &lt;code&gt;--border-color&lt;/code&gt; value.&lt;/p&gt;&lt;p&gt;A gotcha with the first is that you may expect it to use a previously set style for that element in your stylesheet. However, by the time the custom property is evaluated the browser will have already tossed out a previously set, non-inherited value.&lt;/p&gt;&lt;p&gt;In this demo, if &lt;code&gt;--color&lt;/code&gt; is not set, all paragraphs will use &lt;code&gt;unset&lt;/code&gt; behavior. For paragraphs, this evaluates to using &lt;code&gt;inherit&lt;/code&gt; for &lt;code&gt;color&lt;/code&gt;. Since the custom property caused throwing out the previously set paragraph style, the color will inherit from the nearest ancestor instead. You can experiment with adding &lt;code&gt;--color&lt;/code&gt; to the paragraph using dev tools to see it successfully set and used. Adding via dev tools works due to causing a repaint.&lt;/p&gt;
    

    
    &lt;style&gt;
    /* tossed out */
p.unset { color: red }
/* behaves as &#39;inherit&#39; per &#39;unset&#39; rules */
p.unset { color: var(--color) }
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Demonstration of custom properties using &#39;unset&#39; behavior&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* tossed out */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;p.unset&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* behaves as &#39;inherit&#39; per &#39;unset&#39; rules */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;p.unset&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;unset&quot;&gt;My color will inherit from the nearest ancestor where it is set&lt;/p&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;accessing-and-setting-custom-properties-with-javascript&quot;&gt;Accessing and setting custom properties with JavaScript&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#accessing-and-setting-custom-properties-with-javascript&quot; aria-labelledby=&quot;accessing-and-setting-custom-properties-with-javascript&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;There are typically JavaScript counterparts for interacting with CSS, and using JS to dynamically set or update custom properties is kind of a superpower. We can keep the overall style setup in our CSS and update parts of it as needed.&lt;/p&gt;&lt;p&gt;Some opportunities to update custom properties with JavaScript:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;CSS transform values for animations&lt;/li&gt;&lt;li&gt;values within a calc to use viewport dimensions&lt;/li&gt;&lt;li&gt;any number value that can&amp;#39;t be gained in CSS alone&lt;/li&gt;&lt;li&gt;filling the gap for unsupported CSS properties&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To access the value of a custom property within JavaScript, use the following combination of &lt;code&gt;getComputedStyle()&lt;/code&gt; with &lt;code&gt;getPropertyValue()&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.&lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--my-var&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this next demo, we&amp;#39;re using JavaScript to get the width of the paragraph. Then we assign that to the custom property assigned as the hue value within the &lt;code&gt;hsl()&lt;/code&gt; color function. As an aside, this works because &lt;code&gt;hsl&lt;/code&gt; allows any numeric value for hue because it just loops back around the color wheel for numbers greater than 360.&lt;/p&gt;
    

    
    &lt;style&gt;
    .js-color {
  background-color: hsl(var(--hue), 100%, 80%);
  color: black;
  font-size: 1.5rem;
  padding: 1rem;
}

.js-color::after {
  content: &quot; Current: &quot; attr(style);
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;Updating custom properties with JavaScript&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.js-color&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--hue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 80%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.js-color::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; Current: &quot;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.js-color&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;setColor&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--hue&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetWidth&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onresize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; setColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;setColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;p class=&quot;js-color&quot;&gt;Resize your viewport to change my background color (warning: flashing possible).&lt;/p&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const p = document.querySelector(&#39;.js-color&#39;);
const setColor = () =&gt; p.style.setProperty(&#39;--hue&#39;, p.offsetWidth);
window.onresize = setColor;
setColor();
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;combining-preprocessor-variables-and-css-custom-properties&quot;&gt;Combining preprocessor variables and CSS custom properties&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#combining-preprocessor-variables-and-css-custom-properties&quot; aria-labelledby=&quot;combining-preprocessor-variables-and-css-custom-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;As a software engineer who works on design systems, I&amp;#39;ve grown fond of using Sass together with custom variables so that I can use the strengths of each. &lt;/p&gt;&lt;p&gt;In order to use a Sass variable as a custom property value, you need to use interpolation which looks like this:&lt;/p&gt;&lt;pre class=&quot;language-scss&quot;&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--custom-property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;#{$sass-var}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In my work, I&amp;#39;m usually including theming capability. With Sass, we can set static variables using the &lt;code&gt;!default&lt;/code&gt; flag which means they are overridable. Then, we can pass that in to be used as custom property values. Plus we can take advantage of other Sass features like looping to help produce similar groups of properties.&lt;/p&gt;&lt;pre class=&quot;language-scss&quot;&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$color-link&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue &lt;span class=&quot;token statement keyword&quot;&gt;!default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$font-sizes&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;small&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .875rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;normal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;medium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;large&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token statement keyword&quot;&gt;!default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;:root &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--color-link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;#{$color-link}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;@each&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$size&lt;/span&gt;, &lt;span class=&quot;token variable&quot;&gt;$value&lt;/span&gt; in &lt;span class=&quot;token variable&quot;&gt;$font-sizes&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--font-size-&lt;span class=&quot;token variable&quot;&gt;#{$size}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;#{$value}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This setup allows re-theming an application without modifying the core Sass file setup.&lt;/p&gt;
    

    

    

    

    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;summary-of-ways-to-use-custom-properties&quot;&gt;Summary of ways to use custom properties&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#summary-of-ways-to-use-custom-properties&quot; aria-labelledby=&quot;summary-of-ways-to-use-custom-properties&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;color theme values and other design tokens&lt;/li&gt;&lt;li&gt;to update select values across states, as we did for the &lt;code&gt;.btn&lt;/code&gt; demo&lt;/li&gt;&lt;li&gt;allow contextual updates for classes while providing defaults&lt;/li&gt;&lt;li&gt;in partnership with values received from JS&lt;/li&gt;&lt;li&gt;to compensate for preprocessor values being unable to change after being set&lt;/li&gt;&lt;li&gt;...and a whole lot more&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/css-custom-properties/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://lea.verou.me/tag/css-variables/&quot; rel=&quot;noopener noreferrer&quot;&gt;Posts from Lea Verou&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/&quot; rel=&quot;noopener noreferrer&quot;&gt;A strategy guide&lt;/a&gt; to structuring and applying custom properties&lt;/li&gt;&lt;li&gt;More info on &lt;a href=&quot;https://www.smashingmagazine.com/2019/07/css-custom-properties-cascade/&quot; rel=&quot;noopener noreferrer&quot;&gt;how to work with custom properties and the cascade&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The &lt;a href=&quot;https://css-tricks.com/a-complete-guide-to-custom-properties/&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS-Tricks complete guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://css-irl.info/7-uses-for-css-custom-properties/&quot; rel=&quot;noopener noreferrer&quot;&gt;7 practical ideas for using custom properties&lt;/a&gt; from Michelle Barker on CSS-IRL&lt;/li&gt;&lt;li&gt;Also hear &lt;a href=&quot;https://vimeo.com/493848724&quot; rel=&quot;noopener noreferrer&quot;&gt;more about custom properties from Michelle&lt;/a&gt; in this recording from Smashing Meets&lt;/li&gt;&lt;li&gt;Even &lt;a href=&quot;https://ishadeed.com/article/practical-css-variables/&quot; rel=&quot;noopener noreferrer&quot;&gt;more practical use cases&lt;/a&gt; from Ahmad Shadeed&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Details / Summary</title>
    <link href="https://12daysofweb.dev/2021/details-summary/"/>
    <updated>2021-12-14T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/details-summary/</id>
    <content type="html">



&lt;p&gt;Using &lt;code&gt;details&lt;/code&gt; and &lt;code&gt;summary&lt;/code&gt; is appropriate to reveal (aka &amp;quot;disclose&amp;quot;) supplemental information. However, there is a fine line between acceptable and inaccessible usage. While we won&amp;#39;t dive into that in this post, be sure to check the additional resources for more information.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;setting-up-details-and-summary&quot;&gt;Setting up details and summary&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/details-summary/#setting-up-details-and-summary&quot; aria-labelledby=&quot;setting-up-details-and-summary&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Here is the most essential markup for this pattern. The &lt;code&gt;details&lt;/code&gt; element is the parent, and the first child is the &lt;code&gt;summary&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Summary text&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;The content that appears when the details element is open&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which produces the following, which is shown using default browser styles:&lt;/p&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;details&gt;
  &lt;summary&gt;Summary text&lt;/summary&gt;
  &lt;p&gt;The content that appears when the details element is open&lt;/p&gt;
&lt;/details&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;You can also predefine that the details should be &lt;code&gt;open&lt;/code&gt; which means the full content is revealed as the default state.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Important to note&lt;/strong&gt;: you have to remove the &lt;code&gt;open&lt;/code&gt; attribute completely to close the details, not just set it to &amp;quot;false&amp;quot;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;details&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Open summary text&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This content is visible by default&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;details open=&quot;&quot;&gt;
   &lt;summary&gt;Open summary text&lt;/summary&gt;
   &lt;p&gt;This content is visible by default&lt;/p&gt;
&lt;/details&gt; 
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;When the details element open attribute is toggled, it emits a &amp;quot;toggle&amp;quot; event that you can listen for in JavaScript. You can also programmatically add or remove the &lt;code&gt;open&lt;/code&gt; attribute.&lt;/p&gt;
    

    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;JS for the details &quot;toggle&quot; event&lt;/summary&gt;

    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; details &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.js-ds&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;details&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;toggle&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; summary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; details&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;summary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;details&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;open&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;pink&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tomato&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;details class=&quot;js-ds&quot;&gt;
  &lt;summary&gt;Background will change on toggle&lt;/summary&gt;
  &lt;p&gt;Pie wafer apple pie jelly cotton candy chocolate bar icing jelly beans. Apple pie shortbread carrot cake cupcake pastry gummi bears chupa chups lollipop.&lt;/p&gt;
&lt;/details&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    const details = document.querySelector(&#39;.js-ds&#39;);
details.addEventListener(&#39;toggle&#39;, event =&gt; {
  const summary = details.querySelector(&#39;summary&#39;);
  if (details.open) {
    summary.style.backgroundColor = &#39;pink&#39;;
  } else {
    summary.style.backgroundColor = &#39;tomato&#39;;
  }
});
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;styling-considerations-for-details-and-summary&quot;&gt;Styling considerations for details and summary&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/details-summary/#styling-considerations-for-details-and-summary&quot; aria-labelledby=&quot;styling-considerations-for-details-and-summary&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;One of the main issues with browser (aka user agent) styles is that they don&amp;#39;t ship with very good &lt;code&gt;focus&lt;/code&gt; or &lt;code&gt;hover&lt;/code&gt; indicators to reinforce the interactivity. So, let&amp;#39;s fix those two items up first. These styles will be attached to the &lt;code&gt;summary&lt;/code&gt; since that receives those states.&lt;/p&gt;
    

    
    &lt;style&gt;
    summary.styled {
  /* Provide a more expected visual affordance for this clickable element */
  cursor: pointer;
}

summary.styled:hover {
  background-color: #ddd;
}

summary.styled:focus {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;CSS for summary hover and focus&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;summary.styled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Provide a more expected visual affordance for this clickable element */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;summary.styled:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ddd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;summary.styled:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid currentColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;details&gt;
  &lt;summary class=&quot;styled&quot;&gt;I have style!&lt;/summary&gt;
  &lt;p&gt;Gummies topping topping lollipop shortbread candy canes sweet roll. Topping lemon drops sweet muffin lemon drops tootsie roll chupa chups sesame snaps caramels.&lt;/p&gt;
&lt;/details&gt;
    &lt;/div&gt;
    

    

    

    
    &lt;p&gt;We can take it further by customizing the native arrow indicator thanks to a modern CSS selector for &lt;code&gt;::marker&lt;/code&gt; (which also can &lt;a href=&quot;https://moderncss.dev/totally-custom-list-styles/#upgrading-to-css-marker&quot; rel=&quot;noopener noreferrer&quot;&gt;style list bullets&lt;/a&gt;).&lt;/p&gt;
    

    
    &lt;style&gt;
    summary.styled--marker::marker {
  color: magenta;
}
    &lt;/style&gt;
    

    
    &lt;details open=&quot;&quot;&gt;
    &lt;summary&gt;CSS for styling the summary ::marker&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;summary.styled--marker::marker&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; magenta&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;details&gt;
  &lt;summary class=&quot;styled styled--marker&quot;&gt;Even more stylish!&lt;/summary&gt;
  &lt;p&gt;Gummies topping topping lollipop shortbread candy canes sweet roll. Topping lemon drops sweet muffin lemon drops tootsie roll chupa chups sesame snaps caramels.&lt;/p&gt;
&lt;/details&gt;
    &lt;/div&gt;
    

    

    
  

  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;ways-to-use-details-and-summary&quot;&gt;Ways to use details and summary&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/details-summary/#ways-to-use-details-and-summary&quot; aria-labelledby=&quot;ways-to-use-details-and-summary&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;FAQs as long as &lt;a href=&quot;https://adrianroselli.com/2020/05/disclosure-widgets.html#Accordion&quot; rel=&quot;noopener noreferrer&quot;&gt;you aren&amp;#39;t intending them to be an accordion&lt;/a&gt;, which would be an inaccessible use case&lt;/li&gt;&lt;li&gt;A tangential fact within a longer post&lt;/li&gt;&lt;li&gt;An audio or video full transcript&lt;/li&gt;&lt;li&gt;Allowing expanding/collapsing code snippets related to a demo as you&amp;#39;ll see throughout this site&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/details-summary/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Due to there being a narrow range for ensuring your use of details and summary is accessible, I encourage you to check out &lt;a href=&quot;https://adrianroselli.com/2020/05/disclosure-widgets.html&quot; rel=&quot;noopener noreferrer&quot;&gt;Adrian Roselli&amp;#39;s post on Disclosure Widgets&lt;/a&gt;. You&amp;#39;ll learn about a few other similar patterns that would not be appropriate to use &lt;code&gt;details&lt;/code&gt; and &lt;code&gt;summary&lt;/code&gt;, and also find the very simple JS and CSS required if you choose to roll your own.&lt;/p&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>Intersection Observer</title>
    <link href="https://12daysofweb.dev/2021/intersection-observer/"/>
    <updated>2021-12-13T00:00:00.000Z</updated>
    <id>https://12daysofweb.dev/2021/intersection-observer/</id>
    <content type="html">



&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;what-is-the-intersection-observer-api&quot;&gt;What is the Intersection Observer API?&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/intersection-observer/#what-is-the-intersection-observer-api&quot; aria-labelledby=&quot;what-is-the-intersection-observer-api&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;The Intersection Observer (IO) Web API is an asynchronous way to watch the visibility of target elements either within their ancestors or the main viewport. You can then trigger additional events based on the target element&amp;#39;s visibility and position - aka where it&amp;#39;s &amp;quot;intersecting&amp;quot;. Importantly, this &amp;quot;observation&amp;quot; happens off the main thread (that&amp;#39;s the &lt;code&gt;async&lt;/code&gt; part) meaning it can be a more performant alternative to other scroll tracking methods.&lt;/p&gt;&lt;p&gt;While IO is technically an experimental API, it has &lt;a href=&quot;https://caniuse.com/intersectionobserver&quot; rel=&quot;noopener noreferrer&quot;&gt;very good browser support&lt;/a&gt;. Being experimental mostly means it is possible that it could undergo breaking changes. This is good to be aware of, but the core feature set can absolutely start being used today.&lt;/p&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;io-core-features-and-concepts&quot;&gt;IO core features and concepts&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/intersection-observer/#io-core-features-and-concepts&quot; aria-labelledby=&quot;io-core-features-and-concepts&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Let&amp;#39;s consider a scenario where an IO is useful: a sticky table of contents for in-page links where you want to highlight the current section. &lt;/p&gt;&lt;p&gt;Previously, you may have taken measurements between the top of the viewport and the top of each new section, then set up scroll tracking to add a &lt;code&gt;class&lt;/code&gt; to the related link. With IO, we can instead separately observe when each page section intersects say the midpoint of the viewport and then trigger updating an &amp;quot;active&amp;quot; link state.&lt;/p&gt;&lt;p&gt;When using IO, the target element&amp;#39;s intersection is calculated based on three option parameters:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;root&lt;/code&gt;: an ancestor element used for tracking visibility, defaulting to the browser viewport&lt;/li&gt;&lt;li&gt;&lt;code&gt;rootMargin&lt;/code&gt;: enables changing the intersection bounding box using percent or pixel values corresponding to &lt;code&gt;top right bottom left&lt;/code&gt; similar to margin, useful for tracking based on passing for example the midpoint of the ancestor vs. the bottom edge&lt;/li&gt;&lt;li&gt;&lt;code&gt;threshold&lt;/code&gt;: the percentage of the target element that must be visible to trigger the callback, defined as a single number or an array of decimal values between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Once the target is visible based on these parameters, the IO initiates a callback with additional data you can use for your event. One interesting bit of data is the &lt;code&gt;time&lt;/code&gt; in milliseconds between when an observer was started and when the callback was triggered.&lt;/p&gt;&lt;p&gt;A gotcha for IO is the &lt;code&gt;threshold&lt;/code&gt; value. If you select 1, meaning when the element is 100% visible, then the entirety of the element must be visible within the &lt;code&gt;root&lt;/code&gt; at once. Given scrollable areas ranging from phones to mega monitors with varying resolution aspect ratios, 100% is difficult to achieve without failing in some scenarios. The default for threshold is &lt;code&gt;0&lt;/code&gt;, meaning as soon as even 1 pixel is visible the callback will initiate. A more reliable way to change when a callback occurs is to adjust the &lt;code&gt;rootMargin&lt;/code&gt; to reposition at what point the target element needs to intersect the &lt;code&gt;root&lt;/code&gt;.&lt;/p&gt;


  
    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;creating-a-basic-intersection-observer&quot;&gt;Creating a basic Intersection Observer&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/intersection-observer/#creating-a-basic-intersection-observer&quot; aria-labelledby=&quot;creating-a-basic-intersection-observer&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;First, we&amp;#39;ll make sure the API is available:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;IntersectionObserver&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// IO code here&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we&amp;#39;ll initiate the observer, and begin observing our target:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Target to observe&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boxEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;box&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Observer&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boxObserver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IntersectionObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Observing #box&lt;/span&gt;&lt;br /&gt;boxObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boxEl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the callback function, we&amp;#39;ll receive an array of &lt;code&gt;entries&lt;/code&gt; regardless of the number of target elements. In our example, we&amp;#39;re only worried about a single entry, so we can save that by the zero index. We&amp;#39;ll ensure it&amp;#39;s intersecting, remove the observer, and perform our event.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isIntersecting&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  boxObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unobserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  boxEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;intersected&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  boxEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;yellow&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Removing the observer is best if you only need to trigger the callback once. In the scenario of our sticky table of contents, we would want to keep the observer active.&lt;/p&gt;&lt;p&gt;Due to the setup of this tutorial page, we need to scope our observer root to the demo scrollable element of &lt;code&gt;box-root&lt;/code&gt;. Then we&amp;#39;ll also adjust the &lt;code&gt;rootMargin&lt;/code&gt; to pull the bottom up to 50%, meaning our callback won&amp;#39;t trigger until the box has scrolled above the midpoint of the &lt;code&gt;root&lt;/code&gt; element.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rootEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;box-root&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rootEl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;rootMargin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0% 0% -50% 0%&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;style&gt;
    #box-root {
  height: 200px;
  overflow-y: auto;
  border: 1px solid red;
  padding: 1rem;
  font-size: 1.5rem;
}
#box {
  margin: 300px auto;
  border: 2px solid black;
  height: 4rem;
  display: grid;
  place-content: center;
}
.midpoint {
  position: sticky;
  top: 50%;
  width: 100%;
  color: red;
  text-align: center;
  transform: translateY(-50%);
}
    &lt;/style&gt;
    

    
    &lt;details&gt;
    &lt;summary&gt;Basic Intersection Observer&lt;/summary&gt;

    
    &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#box-root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 300px auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.midpoint&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; sticky&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    
    &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;IntersectionObserver&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boxEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;box&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rootEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;box-root&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rootEl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;rootMargin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0% 0% -50% 0%&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isIntersecting&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    boxObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unobserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    boxEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;intersected&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    boxEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;yellow&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boxObserver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IntersectionObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  boxObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boxEl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

    &lt;/details&gt;
    

    
    &lt;div class=&quot;demo&quot;&gt;
      &lt;div id=&quot;box-root&quot;&gt;
&lt;p&gt;Scroll...&lt;/p&gt;
&lt;div class=&quot;midpoint&quot;&gt;midpoint&lt;/div&gt;
&lt;div id=&quot;box&quot;&gt;...&lt;/div&gt;
&lt;/div&gt;
    &lt;/div&gt;
    

    
    &lt;script&gt;
    if (&#39;IntersectionObserver&#39; in window) {
  const boxEl = document.getElementById(&#39;box&#39;);
  const rootEl = document.getElementById(&#39;box-root&#39;);

  const options = {
    root: rootEl,
    rootMargin: &#39;0% 0% -50% 0%&#39;
  }
  const callback = (entries) =&gt; {
    const box = entries[0];
    if (!box.isIntersecting) return;
    boxObserver.unobserve(box.target);
    boxEl.textContent = &#39;intersected&#39;;
    boxEl.style.backgroundColor = &#39;yellow&#39;;
  }

  const boxObserver = new IntersectionObserver(callback, options);
  boxObserver.observe(boxEl);
}
    &lt;/script&gt;
    

    

    
    &lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;ideas-for-using-intersection-observer&quot;&gt;Ideas for using Intersection Observer&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/intersection-observer/#ideas-for-using-intersection-observer&quot; aria-labelledby=&quot;ideas-for-using-intersection-observer&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;p&gt;Besides the sticky table of contents tracking (possibly also familiar to you as &amp;quot;scroll spy&amp;quot;), here are some other ideas.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;analytics events involving visibility or read time&lt;/li&gt;&lt;li&gt;triggering animations&lt;/li&gt;&lt;li&gt;lazy loading assets and scripts&lt;/li&gt;&lt;li&gt;closing out-of-view menus, tooltips, and overlays&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;heading-wrapper h2&quot;&gt;
    &lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;/h2&gt;
    &lt;a href=&quot;https://12daysofweb.dev/2021/intersection-observer/#additional-resources&quot; aria-labelledby=&quot;additional-resources&quot;&gt;
      &lt;span hidden=&quot;&quot;&gt;#&lt;/span&gt;
    &lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;I explored &lt;a href=&quot;https://egghead.io/blog/use-the-intersection-observer-api-for-analytics-events&quot; rel=&quot;noopener noreferrer&quot;&gt;a few different tracking methods&lt;/a&gt; in the context of gathering analytics events&lt;/li&gt;&lt;li&gt;Travis Almand provides &lt;a href=&quot;https://css-tricks.com/an-explanation-of-how-the-intersection-observer-watches/&quot; rel=&quot;noopener noreferrer&quot;&gt;a deep investigation into IO&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Preethi provides &lt;a href=&quot;https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/&quot; rel=&quot;noopener noreferrer&quot;&gt;several practical use cases for IO&lt;/a&gt; like lazy loading or pausing out-of-view videos&lt;/li&gt;&lt;/ul&gt;
    

    

    

    

    

    
  


</content>
  </entry>
  <entry>
    <title>12 Days of Web</title>
    <link href="https://12daysofweb.dev/"/>
    <updated>2025-01-13T20:40:02.099Z</updated>
    <id>https://12daysofweb.dev/</id>
    <content type="html">
</content>
  </entry>
  <entry>
    <title>12 Days of Web 2021</title>
    <link href="https://12daysofweb.dev/2021/"/>
    <updated>2025-01-13T20:40:02.079Z</updated>
    <id>https://12daysofweb.dev/2021/</id>
    <content type="html">
</content>
  </entry>
  <entry>
    <title>12 Days of Web 2023</title>
    <link href="https://12daysofweb.dev/2023/"/>
    <updated>2025-01-13T20:40:02.079Z</updated>
    <id>https://12daysofweb.dev/2023/</id>
    <content type="html">
</content>
  </entry>
  <entry>
    <title>12 Days of Web 2022</title>
    <link href="https://12daysofweb.dev/2022/"/>
    <updated>2025-01-13T20:40:02.079Z</updated>
    <id>https://12daysofweb.dev/2022/</id>
    <content type="html">
</content>
  </entry>
  
</feed>