<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Una Kravets on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Una Kravets</name>
  </author>
  <link href="https://web.dev/authors/una/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/c4bzyDkOZ9MhBaqp0HfW.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Developer Advocate for CSS, UI &amp;amp; DevTools at Chrome</subtitle>
  
  
  <entry>
    <title>Container queries land in stable browsers</title>
    <link href="https://web.dev/cq-stable/"/>
    <updated>2023-02-14T00:00:00Z</updated>
    <id>https://web.dev/cq-stable/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-good-bg color-state-good-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 128 128&quot; style=&quot;enable-background:new 0 0 128 128&quot; xml:space=&quot;preserve&quot;&gt;&lt;path d=&quot;M7.5 123.3c2.2 2.4 11.6-1.9 19-5.3C32 115.4 54 106.3 65 101.6c3-1.2 7.3-2.9 10.4-7 2.8-3.6 10-19-4.6-34.7-15-16-30.4-11.5-36.2-7.5A28.5 28.5 0 0 0 27.3 63c-5.2 11.6-12.7 32.9-15.7 41.3-2.3 6.1-6.4 16.5-4.1 19z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M18 86.8s.7 6.5 6.1 14.6c6.3 9.6 15 11.2 15 11.2l-5.8 2.4s-6.5-2-12.7-10.4c-3.8-5.3-5-11.6-5-11.6l2.3-6.2zm-5.6 15.4s1.5 5.6 4.7 9.7c3.8 5 8.6 6.5 8.6 6.5l-4.5 2s-3.3-.8-7-5.5c-2.9-3.5-3.7-7.6-3.7-7.6l1.9-5.1z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M10 116.4c-.2-.5-.2-1 0-1.4l25.4-53 4.2 16-26.8 38.7c-.7 1-2.3 1-2.8-.2z&quot; style=&quot;opacity:.44&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M41.6 83.2c12 14 25.5 12.2 30 8.6 4.5-3.5 8.1-15.6-3.7-29.3C55.3 48.2 41.3 52.2 38 55.3s-7.4 15.1 3.5 27.9z&quot; style=&quot;fill: var(--color-state-good-bg);&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M82.5 89c-4.3-3.7-6.6-3-9.7-1.8a26 26 0 0 1-18.9 0l2.6-6.2c5 1.7 8.7 1 12-1 4-2.4 9.6-5.6 18.3 1.6 3.6 3 7.3 5.1 10 4.2 2-.7 3-3.6 3.6-6l.2-1.3c.4-3.7 1.2-11.6 7.1-15.7 6.4-4.3 13-4.3 13-4.3l1.2 12c-3-.5-5.2.1-7 1-6.7 3.8-.8 18.2-11.3 23-10.1 4.8-18.4-3.3-21-5.6zM45.4 73.7l-4.3-3.9c8-8.9 5.8-15.4 4.3-20.2A26.4 26.4 0 0 1 44 38.8c-3-3.8-4.4-7.8-4.5-8-1.9-5.7-.5-11.2 2.8-16.4C48.7 4 60.5 4 60.5 4l4 10.5c-3-.1-12.8 0-15.8 4.8-3.8 6-1.3 9.6-1.2 10 .8-1 1.5-1.7 2.2-2.3 4.8-4.2 9-4.8 11.6-4.6a11 11 0 0 1 7.6 4.2c2 2.7 3 6.2 2.3 9.4a11 11 0 0 1-5.8 7.4 16 16 0 0 1-13 1.5v.3l.6 2c1.8 5.4 5 14.1-7.6 26.5zm7.4-37.5c.5.4 1.1.8 1.8 1 2 .8 4.4.6 7-.8 1.5-.9 1.7-1.7 1.7-2 .2-.9 0-2-.7-2.8a2.8 2.8 0 0 0-2-1.2c-1.6-.2-3.6.8-5.6 2.6-1 .9-1.7 2-2.3 3.2zm10 39.1-6.2-.1s3-16.7 12.5-19.5c1.8-.5 3.7-1 5.7-1.3l4-.8c.1-1.6-.5-3.6-1.3-5.9-.6-1.7-1.2-3.5-1.5-5.5-.6-3.9.4-7.3 3-9.6 3-2.9 7.9-3.8 13.4-2.5 3.2.7 5.5 2.2 7.6 3.6 2.9 2 4.6 3 8.2.5 4.3-2.9-1.4-14.3-4.4-21l11.3-4.6c1.5 3.3 8.8 20.3 4 30a11.5 11.5 0 0 1-8.1 6.2c-8 1.8-12.6-1.3-16-3.6-1.6-1-3-1.9-4.6-2.3-10.6-3 4.2 12.6-2.7 19.6-4.2 4.2-14.4 5.3-15 5.5-6.6 1.6-10 11.3-10 11.3z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M44 38.8c-.2 2.2-.3 3.5.3 6.4 2.7 2 8.7 2 8.7 2l-.6-2v-.3c-6.1-3-8.4-6.1-8.4-6.1zm-12.5 9.8-10.3-5 5.1-7.5 8.2 5.4zm-15.2-14A26 26 0 0 1 5 28.9l5.2-6c1.6 1.2 5 3.5 7.2 3.8l-1.1 7.9zM25.6 21.3 18 18.8a18 18 0 0 0 .7-8.3l7.9-1.3c.6 4 .3 8.2-1 12zM73 15.3l7.9-1.7L83 23.9l-7.8 1.7zM92.5 17.8 87 12c2.8-2.8 3.5-6.3 3.5-6.4L98.4 7c-.1.6-1.1 6.3-6 10.9zM95.5 48.6l7-2.2 2.3 7.7-7 2.1zM97.5 113l-7.9-1c.3-2.7-1.8-6.2-2.4-7l6.4-4.8c.5.6 4.7 6.4 4 12.8zM120.4 102.9c-3-.5-6-.6-9.1-.5l-.3-8c3.5-.2 7 0 10.6.6l-1.2 7.9zM109.6 113.9l5.6-5.7 7.8 7.6-5.6 5.7zM93.1 63.3 99 70l-6.6 5.8-5.8-6.6z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt; &lt;/span&gt;&lt;strong&gt;Celebration&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; This web feature is now available in all three major browser engines! &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Container query love is in the air! This Valentine’s day, size container queries and container query units are stable in all modern browsers.&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 105, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      105
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 110, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      110
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 105, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      105
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 16, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      16
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/@container#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;With container queries you can query  the styling information of a parent element, such as its &lt;code&gt;inline-size&lt;/code&gt;. With media queries, you could query the size of the viewport,  container queries enable components that can change based on where they are in the UI.&lt;/p&gt;
&lt;img alt=&quot;Media queries vs container queries.&quot; decoding=&quot;async&quot; height=&quot;388&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/hmzfwE5nyg017bX0GEeP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Container queries are especially handy for responsive design and reusable components. For example, enabling a card component that can lay out in one way when placed in a sidebar, and in a different configuration within a product grid.&lt;/p&gt;
&lt;h2 id=&quot;using-container-queries&quot;&gt;Using container queries &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cq-stable/#using-container-queries&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To use container queries, first set containment on a parent element. Do this by setting a &lt;code&gt;container-type&lt;/code&gt; on the parent container, or use the &lt;code&gt;container&lt;/code&gt; shorthand to give it both a type and name simultaneously:&lt;/p&gt;
&lt;div&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&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; card / 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;/div&gt;&lt;p&gt;Setting the &lt;code&gt;container-type&lt;/code&gt; to &lt;code&gt;inline-size&lt;/code&gt; queries the inline-direction size of the parent. In latin languages like English, this would be the width of the card, as the text flows inline from left to right.&lt;/p&gt;
&lt;p&gt;Now, you can use that container to apply styles to any of its children using &lt;code&gt;@container&lt;/code&gt;:&lt;/p&gt;
&lt;div&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-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;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; 1fr 1fr&lt;span class=&quot;token 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;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400px&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-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;grid-template-columns&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;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&gt;&lt;div class=&quot;codepen-embed-wrap&quot; style=&quot;height: 600px; width: 100%&quot;&gt;
&lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi;&quot; loading=&quot;lazy&quot; src=&quot;https://codepen.io/web-dot-dev/embed/ZEMzNGj?height=600&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen ZEMzNGj by web-dot-dev on Codepen&quot;&gt;See the Pen &lt;a href=&quot;https://codepen.io/web-dot-dev/embed/ZEMzNGj&quot;&gt;Pen ZEMzNGj by web-dot-dev on Codepen&lt;/a&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/2MWkjhnK2TLqZ3S63NfK.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Additionally, you can use &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Container_Queries#container_query_length_units&quot; rel=&quot;noopener&quot;&gt;container query length unit values&lt;/a&gt; in the same way that you would viewport-based unit values. The difference being that the container units correspond to the container rather than the viewport. The following example demonstrates responsive typography using container query units and the &lt;code&gt;clamp()&lt;/code&gt; function to give a minimum and maximum size value:&lt;/p&gt;
&lt;div&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-child 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;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; 15cqi&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 4rem&lt;span class=&quot;token punctuation&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&gt;&lt;p&gt;The &lt;code&gt;15cqi&lt;/code&gt; above refers to 15% of the container’s inline size. The &lt;code&gt;clamp()&lt;/code&gt; function gives this a minimum value of 2rem, and a maximum of 4rem. In the meantime, if &lt;code&gt;15cqi&lt;/code&gt; is between these values, the text will shrink and grow correspondingly.&lt;/p&gt;
&lt;h2 id=&quot;a-container-query-valentine&quot;&gt;A container query Valentine &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cq-stable/#a-container-query-valentine&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To celebrate the container query love this holiday, we’ve made a Valentine for you all to enjoy, regardless of what (latest version) stable browser you’re viewing this in!&lt;/p&gt;
&lt;div class=&quot;codepen-embed-wrap&quot; style=&quot;height: 700px; width: 100%&quot;&gt;
&lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi;&quot; loading=&quot;lazy&quot; src=&quot;https://codepen.io/web-dot-dev/embed/rNrbPQw?height=700&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen rNrbPQw by web-dot-dev on Codepen&quot;&gt;See the Pen &lt;a href=&quot;https://codepen.io/web-dot-dev/embed/rNrbPQw&quot;&gt;Pen rNrbPQw by web-dot-dev on Codepen&lt;/a&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/ge0SICG5Hoyy6EEm4zpv.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>Building Designcember</title>
    <link href="https://web.dev/how-we-built-designcember/"/>
    <updated>2021-12-28T00:00:00Z</updated>
    <id>https://web.dev/how-we-built-designcember/</id>
    <content type="html" mode="escaped">&lt;p&gt;In the spirit of December and the many calendars that folks use to countdown and celebrate, we wanted to highlight web content from the community and the Chrome team. Every day, we highlighted one piece of UI-development and design-related content, totaling 31 highlights, among which were 26 new demo sites, tools, announcements, podcasts, videos, articles, and case studies.&lt;/p&gt;
&lt;p&gt;See the full experience at &lt;a href=&quot;https://designcember.com/&quot; rel=&quot;noopener&quot;&gt;designcember.com&lt;/a&gt;.&lt;/p&gt;
&lt;img alt=&quot;The Designcember site.&quot; decoding=&quot;async&quot; height=&quot;1034&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/v8kOpJVC6fygzllNjUpC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our goal was to deliver an accessible, whimsical, modern, and responsive web experience in as few bytes as possible. We wanted to highlight new responsive APIs like container queries, and include a beautiful example of a dark mode in a design-focused and asset-heavy website. To achieve this, we compressed files, offered multiple formats, used build tools optimized for static site generation, shipped a new polyfill, and more.&lt;/p&gt;
&lt;h2 id=&quot;starting-with-whimsy&quot;&gt;Starting with whimsy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#starting-with-whimsy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The idea around the Designcember calendar site was to function as a showcase for all the work we wanted to spotlight throughout the month of December, while acting like a demo site itself. We decided to build a responsive apartment building that could get taller and more narrow, or shorter and wider, with windows that rearranged themselves within the frame. Each window represented one day (and thus, one piece of content).
We worked with illustrator &lt;a href=&quot;https://www.byalicelee.com/&quot; rel=&quot;noopener&quot;&gt;Alice Lee&lt;/a&gt; to bring our vision to life.&lt;/p&gt;
&lt;img alt=&quot;Sketches of the Designcember page skeleton.&quot; decoding=&quot;async&quot; height=&quot;618&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/rO328nH0xEtVpwbXeYSi.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Alice was inspiring, sharing processes and sketches that were exciting even in their early concepts. While she worked on the art, we hacked on the architecture. Early discussions were around the macro layout, the building, and its windows. How would the windows adapt to one, two, or three columns as more viewport space became available? How far could they shrink or stretch? What would the maximum size of the building be? How much would the windows shift?&lt;/p&gt;
&lt;p&gt;Here&#39;s a preview of a responsive prototype using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/grid-auto-flow&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;grid-auto-flow: dense&lt;/code&gt;&lt;/a&gt; showing how windows could be auto placed by the grid algorithm. We quickly realized that while aspect-ratio grids performed beautifully to showcase art, they didn’t provide an opportunity to let the windows grow and shrink into non-uniform available space and showcase the power of container queries.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Animation that shows how this wireframe responds to different screen sizes.&quot; decoding=&quot;async&quot; height=&quot;552&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/Ktw3eAZCo6p5avjO6xdm.gif?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;
   &lt;a href=&quot;https://codepen.io/argyleink/pen/189adacf9be3eb2348308d904d493143?editors=1100&quot;&gt;Check out this demo on CodePen.&lt;/a&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once the general grid was relatively stable and communicated a sense of direction for the responsiveness of the building and its windows, we could focus on a single window. Some windows stretched, shrank, squeezed, grew, and re-composed themselves more than others in the grid.&lt;/p&gt;
&lt;img alt=&quot;Wireframes showing how the windows display at different breakpoints.&quot; decoding=&quot;async&quot; height=&quot;812&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/iJWU8JYwUhpeXafZ434y.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Each window would need to handle a certain amount of resize turbulence. Below is a prototype of a window demonstrating its responsiveness to turbulence, showing how much we could expect each interactive window to adjust.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/2F6S98FvsNhviuBvtJcI.mov&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;window-animation-with-spritesheets&quot;&gt;Window animation with spritesheets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#window-animation-with-spritesheets&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some windows have animations to bring extra interaction to the experience. The animations are hand-drawn, frame by frame, in Photoshop. Each frame is exported, turned into a spritesheet with this
&lt;a href=&quot;https://www.toptal.com/developers/css/sprite-generator/&quot; rel=&quot;noopener&quot;&gt;spritesheet generator&lt;/a&gt;, then optimized with Squoosh. The CSS animation then uses &lt;code&gt;background-position-x&lt;/code&gt; and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/animation-timing-function&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;animation-timing-function&lt;/code&gt;&lt;/a&gt; as shown in the following example.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;.una&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 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;/day1/una_sprite.webp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; 0% 0%&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; 400% 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;.day:is(:hover, :focus-within) .una&lt;/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; una-wave .5s &lt;span class=&quot;token function&quot;&gt;steps&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; alternate infinite&lt;span class=&quot;token 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; una-wave&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;span class=&quot;token property&quot;&gt;background-position-x&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 selector&quot;&gt;25%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background-position-x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 300%&lt;span class=&quot;token punctuation&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;50%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background-position-x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200%&lt;span class=&quot;token punctuation&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;75%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background-position-x&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 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&gt;&lt;img alt=&quot;Animation showing the window for day one.&quot; decoding=&quot;async&quot; height=&quot;933&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/wQurazNt80vsmII3rdnT.gif?auto=format&amp;w=1600 1600w&quot; style=&quot;max-width: 400px; margin: 1em auto;&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Some animations, such as the &lt;a href=&quot;https://designcember.com/#6th&quot; rel=&quot;noopener&quot;&gt;piggy bank of day six&lt;/a&gt;, were step-based CSS animations.
We achieved this effect with a similar technique, using &lt;code&gt;steps()&lt;/code&gt;, with the difference being that the keyframes were CSS transform positions instead of background positions.&lt;/p&gt;
&lt;h2 id=&quot;css-masking&quot;&gt;CSS masking &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#css-masking&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some windows had unique shapes. We used
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/mask&quot; rel=&quot;noopener&quot;&gt;masks&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/aspect-ratio&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/a&gt; to help make a scalable, uniquely shaped, and adaptive window.&lt;/p&gt;
&lt;p&gt;To create a mask, such as this one for window eight, some classic Photoshop skills were needed,
plus a little bit of knowledge about how masks on the web work. Let&#39;s look at the window for day eight.&lt;/p&gt;
&lt;img alt=&quot;The window for day eight.&quot; decoding=&quot;async&quot; height=&quot;655&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/ZFET81EyIUsVEofkYDIt.png?auto=format&amp;w=1600 1600w&quot; style=&quot;max-width: 400px; margin: 1em auto;&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To become a mask, the inner four leaf clover type shape has to be isolated as its own shape and filled in the color white. White tells the CSS what content stays, and everything outside the white won&#39;t. In Photoshop, the inside of the window was selected, feathered 1px (to remove aliasing issues), then filled white and exported at the same height and width as the window frame. This way the frame and the mask could be layered directly on top of each other, showing the inner content within the frame as expected.&lt;/p&gt;
&lt;img alt=&quot;Clover mask image&quot; decoding=&quot;async&quot; height=&quot;774&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 776px) 776px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/Jm6F9q8T41Sf6riwNYS7.png?auto=format&amp;w=1552 1552w&quot; style=&quot;max-width: 400px; margin: 1em auto;&quot; width=&quot;776&quot; /&gt;
&lt;p&gt;Once complete, the contents of the window could be modified and would always appear to stay within the custom frame. The following image shows the dark mode version of the window, with a different background gradient and a glow CSS filter applied to the light.&lt;/p&gt;
&lt;img alt=&quot;The window for day eight in dark mode.&quot; decoding=&quot;async&quot; height=&quot;634&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/5F1DOOOGToYyQ8lv6wjW.png?auto=format&amp;w=1600 1600w&quot; style=&quot;max-width: 400px; margin: 1em auto;&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Masking also supports responsive container-query based windows. In window nine, there’s a character who is hidden behind a mask until the window is in a more narrow size. To make sure the user can’t adjust the image out of frame, Alice completed the full character for us. The character is masked within the window, but the plants are not, so another challenge we dealt with was layering masked elements with unmasked layers, and ensuring that they all scaled well together.&lt;/p&gt;
&lt;p&gt;The following image shows what it looks like without the mask on the window and character.&lt;/p&gt;
&lt;img alt=&quot;The image for window nine without the mask.&quot; decoding=&quot;async&quot; height=&quot;319&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 512px) 512px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/jWEL8nIl454zzKMnhyEo.png?auto=format&amp;w=1024 1024w&quot; width=&quot;512&quot; /&gt;
&lt;h2 id=&quot;squooshing-the-art&quot;&gt;Squooshing the art &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#squooshing-the-art&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To maintain the fidelity of the illustration and ensure high definition screens wouldn&#39;t get a blurry user experience, Alice worked at a 3x pixel ratio. The plan was to use imgix and serve optimized images and formats on their server, but we found that manual tweaking with the Squoosh tool could save us 50% or more.&lt;/p&gt;
&lt;img alt=&quot;Using Squoosh to compress images.&quot; decoding=&quot;async&quot; height=&quot;490&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/MSHzLyoiZdAZyy0oVHwo.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Illustration has unique challenges for compression, especially the brush stroke and transparent rough edge style Alice used. We chose to Squoosh each 3x Photoshop exported png image, to a smaller png, webp, and avif. Each file type has its own special compression abilities, and it took compressing more than 50 images to find some common optimization settings.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli&quot; rel=&quot;noopener&quot;&gt;Squoosh CLI&lt;/a&gt; became crucial with over 200 images to optimize—doing all those manually would have taken days. Once we had the common optimization settings, we provided them as command line instructions and batch processed entire folders of PNG images into their WebP and AVIF compressed counterparts.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example AVIF CLI squoosh command used:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx @squoosh/cli --quant &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;enabled&quot;:true,&quot;zx&quot;:0,&quot;maxNumColors&quot;:256,&quot;dither&quot;:1}&#39;&lt;/span&gt; --avif &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;cqLevel&quot;:19,&quot;cqAlphaLevel&quot;:17,&quot;subsample&quot;:1,&quot;tileColsLog2&quot;:0,&quot;tileRowsLog2&quot;:0,&quot;speed&quot;:6,&quot;chromaDeltaQ&quot;:false,&quot;sharpness&quot;:5,&quot;denoiseLevel&quot;:0,&quot;tune&quot;:0}&#39;&lt;/span&gt; image-1.png image-2.png image-3.png&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With optimized artwork checked into the repo, we could start loading them from HTML:&lt;/p&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;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;/day1/inner-frame.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;/day1/inner-frame.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;img&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;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;presentation&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;/day1/inner-frame.png&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;/div&gt;&lt;p&gt;It was repetitive to write the picture source code, so we made an
&lt;a href=&quot;https://github.com/GoogleChromeLabs/designcember/blob/main/src/components/Pic/Pic.astro&quot; rel=&quot;noopener&quot;&gt;Astro component&lt;/a&gt; to embed images with one line of code.&lt;/p&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;Pic&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;day1/inner-frame&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;presentation&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;/div&gt;&lt;h2 id=&quot;screen-reader-and-keyboard-users&quot;&gt;Screen reader and keyboard users &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#screen-reader-and-keyboard-users&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Much of the experience of Designcember is through the art and interactive windows. It was important to us that a keyboard user could use the site and peek into windows, and that screen reader users get a nice narrated experience.&lt;/p&gt;
&lt;p&gt;For example, when embedding the images we used &lt;code&gt;role=&amp;quot;presentation&amp;quot;&lt;/code&gt; to mark the image as presentational for screen readers. We felt that a user experience of between 5 and 12 fractured &lt;code&gt;alt&lt;/code&gt; descriptions was going to be a poor experience. So, we marked the images as presentational and provided an overall window narration. Moving through the windows on a screen reader then has a nice narrative feeling, which we hoped would help deliver the whimsy and fun the site wants to share.&lt;/p&gt;
&lt;p&gt;The following video shows a demo of the keyboard experience. Tab, enter, spacebar, and escape keys are all used to orchestrate focus to and from the window popups and the windows.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/UYNJSy92FLABrsLgz0lz.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The screen reader experience has special ARIA attributes that bring clarity to the content. For example, the links for the days only say &amp;quot;one&amp;quot; or &amp;quot;two&amp;quot;, but with some added ARIA, they are announced as &amp;quot;Day one&amp;quot; and &amp;quot;Day two.&amp;quot; Furthermore, all the images are summarized in a single label so each window has a description.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/bKYH0xxOJkwh0RTMGuAG.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;astro,-static-first,-component-driven-site-generator&quot;&gt;Astro, static first, component-driven site generator &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#astro,-static-first,-component-driven-site-generator&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://astro.build/&quot; rel=&quot;noopener&quot;&gt;Astro&lt;/a&gt; made it easy for the team to work together on the site. The component model was familiar to both Angular and React developers, while the scoped classname style system helped each developer know their work on a window wouldn&#39;t conflict with anyone else.&lt;/p&gt;
&lt;h3 id=&quot;days-as-components&quot;&gt;Days as components &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#days-as-components&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/designcember/blob/main/src/components/Days/Day1.astro&quot; rel=&quot;noopener&quot;&gt;Each day was a component&lt;/a&gt; that fetched status from a
&lt;a href=&quot;https://github.com/GoogleChromeLabs/designcember/blob/main/src/components/Days/day.store.js&quot; rel=&quot;noopener&quot;&gt;build time data store&lt;/a&gt;. This let us run template logic before the HTML reached the browser. The logic would determine if the day should show its tooltip or not, as inactive days don&#39;t have pop ups.&lt;/p&gt;
&lt;p&gt;Builds are run every hour and the build time data store would unlock a new day when the build server was past midnight. These self-updating and self-sufficient little systems keep the site up to date.&lt;/p&gt;
&lt;h3 id=&quot;scoped-styles-and-open-props&quot;&gt;Scoped styles and Open Props &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#scoped-styles-and-open-props&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Astro &lt;a href=&quot;https://docs.astro.build/guides/styling/&quot; rel=&quot;noopener&quot;&gt;scopes styles written inside its component model&lt;/a&gt;, which made distributing the workload amongst many team members easier, and also made using &lt;a href=&quot;https://open-props.style/&quot; rel=&quot;noopener&quot;&gt;Open Props&lt;/a&gt; fun. The &lt;a href=&quot;https://unpkg.com/open-props/normalize.min.css&quot; rel=&quot;noopener&quot;&gt;Open Props normalize.css&lt;/a&gt; styles came in handy with the adaptive (light and dark) theme, as well as helping wrangle content like paragraphs and headers.&lt;/p&gt;
&lt;p&gt;As early adopters of Astro, we ran into a few snags with PostCSS. For example, we weren&#39;t able to update to the
&lt;a href=&quot;https://astro.build/blog/astro-021-release/&quot; rel=&quot;noopener&quot;&gt;latest Astro version&lt;/a&gt; due to too many build issues. More time could be spent here, optimizing the build and developer workflows.&lt;/p&gt;
&lt;h2 id=&quot;flexible-containers&quot;&gt;Flexible containers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#flexible-containers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some windows grow and shrink, maintaining &lt;a href=&quot;https://web.dev/aspect-ratio&quot;&gt;aspect ratio&lt;/a&gt; to preserve their art. We used some other windows to showcase the power of component-based architecture with container queries. Container queries meant windows could own their individual responsive styling information and readjust based on their own sizes. Some windows went from narrow to wide and needed to adjust the size of the media within them, as well as the placement of that media.&lt;/p&gt;
&lt;img alt=&quot;A demonstration of how the windows change as they have more space.&quot; decoding=&quot;async&quot; height=&quot;383&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ssFflPRQrTum3fbwkAWZ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;As more space becomes available for a window, we could adapt the size or child elements of the window to fit. Turned out that in order to fulfill the adaptive windows, container queries wouldn&#39;t just be fun to showcase, they&#39;d be required and drastically simplify orchestrating certain layouts.&lt;/p&gt;
&lt;div&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;.day&lt;/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; 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 selector&quot;&gt;.day &gt; .pane&lt;/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-block-size&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;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;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 220px&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;min-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 300px&lt;span class=&quot;token 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;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 260px&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;min-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 310px&lt;span class=&quot;token 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;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 360px&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;min-block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 450px&lt;span class=&quot;token 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&gt;&lt;aside class=&quot;aside flow bg-state-warn-bg color-state-warn-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block color-state-warn-text&quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Warning sign&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M23 21L12 2 1 21h22zm-12-3v-2h2v2h-2zm0-4h2v-4h-2v4z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The container query spec has since added a required &lt;code&gt;size()&lt;/code&gt; wrapper around width and height queries. This syntax language is still a work in progress, but the polyfill described later in this article supports both syntaxes. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;This approach is different from maintaining an aspect ratio. It offers more control and more opportunities. At a certain size, many children shift around to adapt to a new layout.&lt;/p&gt;
&lt;p&gt;Container queries also allowed us to support block-direction (vertical) containment, so as a window grew in length, we could adjust its styles to fit appropriately. This is seen in the height-based queries, which we used standalone, and in addition to width-based queries:&lt;/p&gt;
&lt;div&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;.person&lt;/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-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;margin-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 25% 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-inline-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -15%&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; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--layer-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;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;&lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 350px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&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; 425px&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;place-self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center flex-end&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; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;inset-block-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -15%&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; -2%&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; -25%&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; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--layer-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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We also used container queries to show and hide detail as the art became increasingly crowded at smaller sizes, and emptier at wider sizes. Window nine is a great example of where this came into play:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/rXfci0RECfk5six1UTGv.mov&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;cross-browser-support&quot;&gt;Cross-browser support &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#cross-browser-support&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To create a great modern cross-browser experience, especially for experimental APIs like container queries, we need a great polyfill. We sent a call out to our team, and Surma spearheaded a build for a new &lt;a href=&quot;https://www.npmjs.com/package/container-query-polyfill&quot; rel=&quot;noopener&quot;&gt;container query polyfill&lt;/a&gt;. The polyfill relies on &lt;a href=&quot;https://caniuse.com/resizeobserver&quot; rel=&quot;noopener&quot;&gt;ResizeObserver&lt;/a&gt;, &lt;a href=&quot;https://caniuse.com/mutationobserver&quot; rel=&quot;noopener&quot;&gt;MutationObserver&lt;/a&gt; and the CSS &lt;a href=&quot;https://caniuse.com/css-matches-pseudo&quot; rel=&quot;noopener&quot;&gt;:is() function&lt;/a&gt;. Therefore, all modern browsers support the polyfill, specifically Chrome and Edgefrom version 88, Firefox from version 78, and Safari from version 14. Using the polyfill allows any of the following syntaxes:&lt;/p&gt;
&lt;div&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 all equivalent */&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 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; 200px&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;/* ... */&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 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;= 200px&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;/* ... */&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 atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 200px&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;/* ... */&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&gt;&lt;h2 id=&quot;dark-mode&quot;&gt;Dark mode &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#dark-mode&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;img alt=&quot;The light and dark mode versions of the Designcember site, side-by-side.&quot; decoding=&quot;async&quot; height=&quot;401&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/KKWJFNWYiKBiOkpg1fBK.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;One last touch that was essential for the Designcember website was a beautiful dark theme. We wanted to show how you could use art itself to be an active participant in creating a great dark mode experience. For this, we adjusted the background styles of each window itself programmatically, and used as much CSS as made sense when creating the window art. Most of the backgrounds were CSS gradients, so that it would be easier to adjust their color values. We then layered the art on top of these.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/gBrdHzLwdDckE9pgxK5L.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-easter-eggs&quot;&gt;Other Easter eggs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#other-easter-eggs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;personal-touches&quot;&gt;Personal touches &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#personal-touches&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We added a few personal touches to the page to give the site more personality. The first was the cast of characters, drawn from inspiration from our team. We also included a throwback-style cursor on inactive days and played around with the favicon style.&lt;/p&gt;
&lt;img alt=&quot;Custom cursor styles and favicon options&quot; decoding=&quot;async&quot; height=&quot;408&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/qjXfDOxsGXIIE57cXnyr.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;functional-touches&quot;&gt;Functional touches &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-we-built-designcember/#functional-touches&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the additional functional touches is a &amp;quot;Jump to Today&amp;quot; functionality, with a bird that sits on top of the building. Clicking or hitting enter on this bird jumps you down on the page to the current day of the month, so you can quickly get to the latest launches.&lt;/p&gt;
&lt;p&gt;Designcember.com also has a special print stylesheet where we&#39;re essentially serving a specific image that works best on 8.5&amp;quot; x 11&amp;quot; paper so you can print the calendar out yourself and stay festive all year long.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Poster-sized print of the calendar design.&quot; decoding=&quot;async&quot; height=&quot;1066&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/FQ1XPh1UbVvlvNzn7PtC.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;Una holding a large print of the calendar.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All in all, a ton of work went into creating a fun, whimsical modern web experience to celebrate UI development all month long in December. We hope you enjoyed it!&lt;/p&gt;
&lt;img alt=&quot;Parts of the calendar with annotations and visual notes&quot; decoding=&quot;async&quot; height=&quot;957&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/aNlNdEYdk4t9yteQm8GK.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;</content>
    <author>
      <name>Adam Argyle</name>
    </author><author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>State of CSS 2021</title>
    <link href="https://web.dev/state-of-css-2021/"/>
    <updated>2021-12-17T00:00:00Z</updated>
    <id>https://web.dev/state-of-css-2021/</id>
    <content type="html" mode="escaped">&lt;p&gt;The &lt;a href=&quot;https://2021.stateofcss.com/en-US/&quot; rel=&quot;noopener&quot;&gt;State of CSS 2021&lt;/a&gt; survey ran for the third year in a row, and reached over 8,000 developers worldwide. Let&#39;s  look at some of the results and how they map to plans browsers have for adding CSS features in 2022.&lt;/p&gt;
&lt;h1&gt;Feature usage and awareness&lt;/h1&gt;
&lt;p&gt;For some features, there&#39;s a clear trend in usage and awareness year-over-year. &lt;a href=&quot;https://2021.stateofcss.com/en-US/features/layout/#grid&quot; rel=&quot;noopener&quot;&gt;CSS grid&lt;/a&gt; is an example of this.&lt;/p&gt;
&lt;img alt=&quot;Awareness of CSS Grid in State of CSS over time. The usage has grown from 55% to 83% between 2019 and 2021.&quot; decoding=&quot;async&quot; height=&quot;360&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/i1D3fea4SShlOWR9GvCYL83Xw822/JCCwRm9rKUZQikjZhiXj.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This matches the trend for CSS Grid in the &lt;a href=&quot;https://almanac.httparchive.org/en/2021/css#flexbox-and-grid-adoption&quot; rel=&quot;noopener&quot;&gt;2021 Web Almanac&lt;/a&gt; and in Chrome&#39;s &lt;a href=&quot;https://www.chromestatus.com/metrics/feature/timeline/popularity/1693&quot; rel=&quot;noopener&quot;&gt;usage metrics&lt;/a&gt;.
If you haven&#39;t used CSS Grid, now is a great time to &lt;a href=&quot;https://web.dev/learn/css/grid/&quot;&gt;learn it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As more developers use grid, &lt;a href=&quot;https://2021.stateofcss.com/en-US/features/layout/#subgrid&quot; rel=&quot;noopener&quot;&gt;awareness of subgrid&lt;/a&gt; is also growing. Subgrid is already available in Firefox and will land in Chrome as part of the work by the Microsoft Team on &lt;a href=&quot;https://blogs.windows.com/msedgedev/2021/08/10/compat2021-css-grid-gridng/&quot; rel=&quot;noopener&quot;&gt;GridNG&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other features with strong growth in usage and awareness are
&lt;a href=&quot;https://2021.stateofcss.com/en-US/features/layout/#aspect_ratio&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://2021.stateofcss.com/en-US/features/interactions/#scroll_snap&quot; rel=&quot;noopener&quot;&gt;scroll snap&lt;/a&gt;, and &lt;a href=&quot;https://2021.stateofcss.com/en-US/features/other-features/#variables&quot; rel=&quot;noopener&quot;&gt;custom properties&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Browser compatibility&lt;/h1&gt;
&lt;p&gt;Browser compatibility is a common pain point for web developers and, to learn more about what CSS features cause the most issues, the survey asked, &amp;quot;Are there any CSS features you have difficulties using because of differences between browsers?&amp;quot;&lt;/p&gt;
&lt;img alt=&quot;Survey results for features with differences between browsers. The top three responses are grid, flexbox gap, and subgrid.&quot; decoding=&quot;async&quot; height=&quot;909&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/rjslQmdTEZr8lNz0EbHC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt; 
&lt;p&gt;Survey results like these help guide prioritization for browser vendors. Many of the features are part of the &lt;a href=&quot;https://web.dev/compat2021-holiday-update/&quot;&gt;Compat 2021 effort&lt;/a&gt; based on the &lt;a href=&quot;https://insights.developer.mozilla.org/reports/mdn-browser-compatibility-report-2020.html&quot; rel=&quot;noopener&quot;&gt;MDN Browser Compatibility Report 2020&lt;/a&gt;, and others like subgrid are now being &lt;a href=&quot;https://github.com/web-platform-tests/interop-2022/issues/1&quot; rel=&quot;noopener&quot;&gt;proposed&lt;/a&gt; as focus areas for Interop 2022.&lt;/p&gt;
&lt;h1&gt;What&#39;s missing in CSS?&lt;/h1&gt;
&lt;p&gt;The survey also asked, &amp;quot;Which feature would you most like to be able to use in CSS today?&amp;quot;&lt;/p&gt;
&lt;img alt=&quot;Survey results for the question what&amp;#x27;s missing in CSS. The top three responses are container queries, parent selector, and browser support.&quot; decoding=&quot;async&quot; height=&quot;617&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/cZesmseagvBYouHVaRJO.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Container Queries was the overall &amp;quot;winner&amp;quot;, matching the &lt;a href=&quot;https://2020.stateofcss.com/en-US/opinions/#currently_missing_from_css&quot; rel=&quot;noopener&quot;&gt;2020 results&lt;/a&gt;. Container queries enable &lt;a href=&quot;https://web.dev/new-responsive/&quot;&gt;component-based responsive&lt;/a&gt; design by allowing elements to query their parent selector for style changes. This is a much more local, specified scope than is currently possible with media queries.&lt;/p&gt;
&lt;p&gt;Chrome is currently working on an experimental implementation, and funding the work of &lt;a href=&quot;https://twitter.com/TerribleMia/&quot; rel=&quot;noopener&quot;&gt;Miriam Suzanne&lt;/a&gt;, as she develops the &lt;a href=&quot;https://drafts.csswg.org/css-contain-3/&quot; rel=&quot;noopener&quot;&gt;specification&lt;/a&gt; in the CSS Working Group. You can try it out by going to &lt;code&gt;about:flags&lt;/code&gt;, searching for, and enabling, the &lt;strong&gt;Container Queries&lt;/strong&gt; flag in Canary, or by using the &lt;a href=&quot;https://www.npmjs.com/package/container-query-polyfill&quot; rel=&quot;noopener&quot;&gt;container query polyfill&lt;/a&gt;. You can learn more about container queries, as well as see some demos that use them in the latest series of &lt;a href=&quot;https://www.youtube.com/watch?v=gCNMyYr7F6w&amp;amp;list=PLNYkxOF6rcIDI0QtJvW6vKonTxn6azCsD&amp;amp;index=14&quot; rel=&quot;noopener&quot;&gt;Designing in the Browser&lt;/a&gt; or trying them yourself &lt;a href=&quot;https://codepen.io/web-dot-dev/pen/LYzxgxP&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;gCNMyYr7F6w&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h1&gt;Learn more&lt;/h1&gt;
&lt;p&gt;Please see the &lt;a href=&quot;https://2021.stateofcss.com/en-US/&quot; rel=&quot;noopener&quot;&gt;full report&lt;/a&gt; to learn more, see recommended resources, or dig into the data yourself.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://sachagreif.com/&quot; rel=&quot;noopener&quot;&gt;Sacha Greif&lt;/a&gt; for running the survey, and to the over 8,000 web developers who generously took the time to answer it.&lt;/p&gt;
</content>
    <author>
      <name>Philip Jägenstedt</name>
    </author><author>
      <name>Rachel Andrew</name>
    </author><author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>CSS for Web Vitals</title>
    <link href="https://web.dev/css-web-vitals/"/>
    <updated>2021-06-02T00:00:00Z</updated>
    <id>https://web.dev/css-web-vitals/</id>
    <content type="html" mode="escaped">&lt;p&gt;The way you write your styles and build layouts can have a major impact on &lt;a href=&quot;https://web.dev/learn-core-web-vitals/&quot;&gt;Core
Web Vitals&lt;/a&gt;. This is particularly true for
&lt;a href=&quot;https://web.dev/cls&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/lcp&quot;&gt;Largest Contentful
Paint (LCP)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This article covers CSS-related techniques for optimizing Web Vitals. These
optimizations are broken down by different aspects of a page: layout, images,
fonts, animations, and loading. Along the way, we&#39;ll explore improving an
&lt;a href=&quot;https://codepen.io/una/pen/vYyLKvY&quot; rel=&quot;noopener&quot;&gt;example page&lt;/a&gt;:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of example site&quot; decoding=&quot;async&quot; height=&quot;646&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/pgmpMOmweK7BVBsVkQ5g.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;layout&quot;&gt;Layout &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#layout&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;inserting-content-into-the-dom&quot;&gt;Inserting content into the DOM &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#inserting-content-into-the-dom&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inserting content into a page after the surrounding content has already loaded
pushes everything else on the page down. This causes &lt;a href=&quot;https://web.dev/cls/#layout-shifts-in-detail&quot;&gt;layout
shifts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/cookie-notice-best-practices/&quot;&gt;Cookie notices&lt;/a&gt;, particularly
those placed at the top of the page, are a common example of this problem. Other
page elements that often cause this type of layout shift when they load include
ads and embeds.&lt;/p&gt;
&lt;h4 id=&quot;identify&quot;&gt;Identify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#identify&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Lighthouse &amp;quot;Avoid large layout shifts&amp;quot; audit identifies page elements that
have shifted. For this demo, the results look like this:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse&amp;#x27;s &amp;#x27;Avoid large layout shifts&amp;#x27; audit&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/jaHtgwzDXCjx3vAFOO33.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The cookie notice is not listed in these findings because the cookie notice
itself isn&#39;t shifting when it loads. Rather, it causes the items below it on the
page (that is, &lt;code&gt;div.hero&lt;/code&gt; and &lt;code&gt;article&lt;/code&gt;) to shift. For more information on
identifying and fixing layout shifts, see &lt;a href=&quot;https://web.dev/debugging-layout-shifts&quot;&gt;Debugging Layout
Shifts&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  Lighthouse only analyzes a page&#39;s performance up until the &amp;quot;page load&amp;quot; event. Cookie banners, ads, and other widgets sometimes do not load until after page load. These layout shifts still affect users—even if they are not flagged by Lighthouse.  &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;fix&quot;&gt;Fix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fix&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Place the cookie notice at the bottom of the page using absolute or fixed
positioning.&lt;/p&gt;
&lt;img alt=&quot;Cookie notice displayed at bottom of page&quot; decoding=&quot;async&quot; height=&quot;656&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/YBYLT9jJ9AXrbsaRNVoa.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div&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 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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After:&lt;/p&gt;
&lt;div&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 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; 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;/div&gt;&lt;p&gt;Another way to fix this layout shift would be to reserve space for the cookie
notice at the top of the screen. This approach is equally effective. For more
information, see &lt;a href=&quot;https://web.dev/cookie-notice-best-practices/&quot;&gt;Cookie notice best
practices&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  The cookie notice is one of multiple page elements that are triggering layout shifts when it loads. To help us get a closer look at these page elements, subsequent demo steps will not include the cookie notice.  &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;images&quot;&gt;Images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#images&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;images-and-largest-contentful-paint-lcp&quot;&gt;Images and Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#images-and-largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Images are commonly the Largest Contentful Paint (LCP) element on a page. Other
&lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;page elements that can be the LCP
element&lt;/a&gt; include text blocks
and video poster images. The time at which the LCP element loads determines LCP.&lt;/p&gt;
&lt;p&gt;It&#39;s important to note that a page&#39;s LCP element can vary from page load to page
load depending on the content that is visible to the user when the page is first
displayed. For example, in this demo, the background of the cookie notice, the
hero image, and the article text are some of the potential LCP elements.&lt;/p&gt;
&lt;img alt=&quot;Diagram highlighting the page&amp;#x27;s LCP element in different scenarios.&quot; decoding=&quot;async&quot; height=&quot;498&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/bMoAoohyLOgTqV6B7lHr.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In the example site, the background image of the cookie notice is actually a
large image. To improve LCP, you could instead paint the gradient in CSS, rather
than load an image to create the effect.&lt;/p&gt;
&lt;h4 id=&quot;fix-2&quot;&gt;Fix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fix-2&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Change the &lt;code&gt;.banner&lt;/code&gt; CSS to use a CSS gradient rather than an image:&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div&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;background&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;https://cdn.pixabay.com/photo/2015/07/15/06/14/gradient-845701\_960\_720.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After:&lt;/p&gt;
&lt;div&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;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;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #fbc6ff 20%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #bdfff9 90%&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&gt;&lt;h3 id=&quot;images-and-layout-shifts&quot;&gt;Images and layout shifts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#images-and-layout-shifts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Browsers can only determine the size of an image once the image loads. If the
image load occurs after the page has been rendered, but no space has been
reserved for the image, a layout shift occurs when the image appears. In the
demo, the hero image is causing a layout shift when it loads.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The phenomenon of images causing layout shifts is more obvious in situations where images are slow to load - for example, on a slow connection or when loading an image with a particularly large file size. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;identify-2&quot;&gt;Identify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#identify-2&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To identify images without explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;, use Lighthouse&#39;s
&amp;quot;Image elements have explicit width and height&amp;quot; audit.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse&amp;#x27;s &amp;#x27;Image elements have explicit width and height&amp;#x27; audit&quot; decoding=&quot;async&quot; height=&quot;274&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wDGRVi7JaUOTjD9ODOk9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In this example, both the hero image and article image are missing &lt;code&gt;width&lt;/code&gt; and
&lt;code&gt;height&lt;/code&gt; attributes.&lt;/p&gt;
&lt;h4 id=&quot;fix-3&quot;&gt;Fix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fix-3&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Set the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes on these images to avoid layout shifts.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&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;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/random/2000x600&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;image to load in&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/random/800x600&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;image to load in&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;/div&gt;&lt;p&gt;After:&lt;/p&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;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/random/2000x600&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;2000&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;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;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;image to load in&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/random/800x600&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;800&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;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;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;image to load in&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;/div&gt;&lt;figure&gt;
  &lt;video&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/j2RDdG43oidUy6AL6LovThjeX9c2/fLUscMGOlGhKnNHef2py.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    The image now loads without causing a layout shift.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Another approach to loading images is to use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/srcset&quot;&gt;&lt;code&gt;srcset&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/sizes&quot;&gt;&lt;code&gt;sizes&lt;/code&gt;&lt;/a&gt; attributes in conjunction with specifying &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes. This has the additional performance advantage of allowing you to serve different sized images to different devices. For more information, see &lt;a href=&quot;https://web.dev/serve-responsive-images/&quot;&gt;Serve responsive images&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;fonts&quot;&gt;Fonts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fonts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fonts can delay text rendering and cause layout shifts. As a result, it is
important to deliver fonts quickly.&lt;/p&gt;
&lt;h3 id=&quot;delayed-text-rendering&quot;&gt;Delayed text rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#delayed-text-rendering&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, a browser will not immediately render a text element if its
associated web fonts have not loaded yet. This is done to prevent a &lt;a href=&quot;https://en.wikipedia.org/wiki/Flash_of_unstyled_content&quot; rel=&quot;noopener&quot;&gt;&amp;quot;flash of
unstyled text&amp;quot; (FOUT)&lt;/a&gt;.
In many situations, this delays &lt;a href=&quot;https://web.dev/fcp&quot;&gt;First Contentful Paint
(FCP)&lt;/a&gt;. In some situations, this delays Largest Contentful
Paint (LCP).&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  By default, Chromium-based and Firefox browsers will &lt;a href=&quot;https://developer.chrome.com/blog/font-display/&quot;&gt;block text rendering for up to 3 seconds&lt;/a&gt; if the associated web font has not loaded; Safari will block text rendering indefinitely. The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#the_font_display_timeline&quot;&gt;block period&lt;/a&gt; begins when the browser requests a web font. If the font has still not loaded by the end of the block period, the browser will render the text using a fallback font and swap in the web font once available.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;layout-shifts&quot;&gt;Layout shifts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#layout-shifts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Font swapping, while excellent for displaying content to the user quickly, has
the potential to cause layout shifts. These layout shifts occur when a web font
and its fallback font take up different amounts of space on the page. Using
similarly proportioned fonts will minimize the size of these layout shifts.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing a layout shift caused by a font swap&quot; decoding=&quot;async&quot; height=&quot;452&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/g0892nhvz3SnSaasaO1b.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    In this example, font swapping caused page elements to shift upwards by five pixels.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;identify-3&quot;&gt;Identify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#identify-3&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To see the fonts that are being loaded on a particular page, open the
&lt;strong&gt;Network&lt;/strong&gt; tab in DevTools and filter by &lt;strong&gt;Font&lt;/strong&gt;. Fonts can be large files, so
only using fewer fonts is generally better for performance.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a font displayed in DevTools&quot; decoding=&quot;async&quot; height=&quot;252&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/Ts38bQtR6x0SDgufA9vz.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To see how long it takes for the font to be requested, click on the &lt;strong&gt;Timing&lt;/strong&gt;
tab. The sooner that a font is requested, the sooner it can be loaded and used.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of &amp;#x27;Timing&amp;#x27; tab in DevTools&quot; decoding=&quot;async&quot; height=&quot;340&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/wfS7qVThKMkGA7SHd439.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To see the request chain for a font, click on the  &lt;strong&gt;Initiator&lt;/strong&gt; tab.
Generally speaking, the shorter the request chain, the sooner the font can be
requested.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of &amp;#x27;Initiator&amp;#x27; tab in DevTools&quot; decoding=&quot;async&quot; height=&quot;189&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/0tau1GQnZfj5vPhzwnIQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h4 id=&quot;fix-4&quot;&gt;Fix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fix-4&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This demo uses the Google Fonts API. Google Fonts provides the option to load
fonts via &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags or an &lt;code&gt;@import&lt;/code&gt; statement. The &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; code snippet
includes a &lt;code&gt;preconnect&lt;/code&gt; resource hint. This should result in faster
stylesheet delivery than using the &lt;code&gt;@import&lt;/code&gt; version.&lt;/p&gt;
&lt;p&gt;At a very high-level, you can think of &lt;a href=&quot;https://www.w3.org/TR/resource-hints/#resource-hints&quot; rel=&quot;noopener&quot;&gt;resource
hints&lt;/a&gt; as a way to hint
to the browser that it will need to set up a particular connection or download a
particular resource. As a result, the browser will prioritize these actions.
When using resource hints, keep in mind that prioritizing a particular action
takes away browser resources from other actions. Thus, resource hints should be
used thoughtfully and not for everything. For more information, see &lt;a href=&quot;https://web.dev/preconnect-and-dns-prefetch/&quot;&gt;Establish
network connections early to improve perceived page
speed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remove the following &lt;code&gt;@import&lt;/code&gt; statement from your stylesheet:&lt;/p&gt;
&lt;div&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;&lt;span class=&quot;token string url&quot;&gt;&#39;https://fonts.googleapis.com/css2?family=Montserrat:wght@400&amp;amp;family=Roboto:wght@300&amp;amp;display=swap&#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;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Add the following &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the document:&lt;/p&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;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;preconnect&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://fonts.googleapis.com&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;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;preconnect&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://fonts.gstatic.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;crossorigin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;https://fonts.googleapis.com/css2?family=Roboto:wght@100&amp;amp;display=swap&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;These link tags instruct the browser to establish an early connection to
the origins used by Google Fonts and to load the stylesheet that
contains the font declaration for Montserrat and Roboto. These &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags
should be placed as early in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; as possible.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  To only load a subset of a font from Google Fonts, add the &lt;a href=&quot;https://developers.google.com/fonts/docs/getting_started&quot;&gt;&lt;code&gt;?text=&lt;/code&gt;&lt;/a&gt; API parameter. For example, &lt;code&gt;?text=ABC&lt;/code&gt; loads only the characters necessary to render &amp;quot;ABC&amp;quot;. This is a good way to reduce the file size of a font.  &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;animations&quot;&gt;Animations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#animations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The primary way that animations affect Web Vitals is when they cause layout
shifts. There are two types of animations that you should avoid using:
&lt;a href=&quot;https://web.dev/animations-guide/#triggers&quot;&gt;animations that trigger layout&lt;/a&gt; and
&amp;quot;animation-like&amp;quot; effects that move page elements. Typically these animations can
be replaced with more performant equivalents by using CSS properties like
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/transform&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;transform&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/opacity&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;opacity&lt;/code&gt;&lt;/a&gt;, and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/filter&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/a&gt;. For more
information, see &lt;a href=&quot;https://web.dev/animations/&quot;&gt;How to create high-performance CSS
animations&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;identify-4&quot;&gt;Identify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#identify-4&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Lighthouse &amp;quot;Avoid non-composited animations&amp;quot; audit may be helpful for
identifying non-performant animations.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse&amp;#x27;s &amp;#x27;Avoid non-composited animations&amp;#x27; audit&quot; decoding=&quot;async&quot; height=&quot;132&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 512px) 512px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/mXgypW9x3qgvmWDLbIZx.png?auto=format&amp;w=1024 1024w&quot; width=&quot;512&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  The Lighthouse &amp;quot;Avoid non-composited animations&amp;quot; audit only identifies non-performant &lt;em&gt;CSS animations&lt;/em&gt;; JavaScript-driven animations (for example, using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/setInterval&quot;&gt;&lt;code&gt;setInterval()&lt;/code&gt;&lt;/a&gt; to &amp;quot;animate&amp;quot; an element) are bad for performance but will not be flagged by this audit.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;fix-5&quot;&gt;Fix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#fix-5&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Change the &lt;code&gt;slideIn&lt;/code&gt; animation sequence to use &lt;code&gt;transform: translateX()&lt;/code&gt; rather
than transitioning the&lt;code&gt;margin-left&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div&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;.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;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slideIn 1s 1 ease&lt;span class=&quot;token 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; slideIn&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;margin-left&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;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;margin-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;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After:&lt;/p&gt;
&lt;div&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;.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;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slideIn 1s 1 ease&lt;span class=&quot;token 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; slideIn&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;translateX&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 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;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;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;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&gt;&lt;h2 id=&quot;critical-css&quot;&gt;Critical CSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#critical-css&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Stylesheets are render-blocking. This means that the browser encounters a
stylesheet, it will stop downloading other resources until the browser has
downloaded and parsed the stylesheet. This may delay LCP. To improve
performance, consider &lt;a href=&quot;https://css-tricks.com/how-do-you-remove-unused-css-from-a-site/&quot; rel=&quot;noopener&quot;&gt;removing unused
CSS&lt;/a&gt;,
&lt;a href=&quot;https://web.dev/extract-critical-css/&quot;&gt;inlining critical CSS&lt;/a&gt;, and &lt;a href=&quot;https://web.dev/defer-non-critical-css/#optimize&quot;&gt;deferring
non-critical CSS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-web-vitals/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although there is still room for further improvements (for example, using &lt;a href=&quot;https://web.dev/use-imagemin-to-compress-images/&quot;&gt;image
compression&lt;/a&gt; to deliver images
more quickly), these changes have significantly improved the Web Vitals of this
site. If this were a real site, the next step would be to &lt;a href=&quot;https://web.dev/vitals-measurement-getting-started/#measuring-web-vitals-using-rum-data&quot;&gt;collect performance
data from real
users&lt;/a&gt;
to assess whether it is &lt;a href=&quot;https://web.dev/vitals-measurement-getting-started/#data-interpretation&quot;&gt;meeting the Web Vitals thresholds for most
users&lt;/a&gt;.
For more information about Web Vitals, see &lt;a href=&quot;https://web.dev/learn-core-web-vitals/&quot;&gt;Learn Web
Vitals&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Katie Hempenius</name>
    </author><author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>The new responsive: Web design in a component-driven world</title>
    <link href="https://web.dev/new-responsive/"/>
    <updated>2021-05-19T00:00:00Z</updated>
    <id>https://web.dev/new-responsive/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;jUQ2-C5ZNRc&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;responsive-design-today&quot;&gt;Responsive Design Today &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#responsive-design-today&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today, when using the term: &amp;quot;responsive design&amp;quot;, you are most likely thinking
about using media queries to change layout when resizing a design from mobile
size, to tablet size, through to desktop size.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/3KENjI9FiNARctTiKDak.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;But soon, this perception of responsive design may be considered as outdated as
using tables for page layout.&lt;/p&gt;
&lt;p&gt;Viewport-based media queries give you some powerful tools, but lack a lot of
finesse. They lack the ability to respond to user needs, and the ability to
inject responsive styles into components themselves.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; When referring to components for the sake of this article, this means elements, including elements that are made up of other elements, like a card or sidebar. Those components make up our web pages. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;You can use global viewport information to style your components, but they still
don&#39;t own their styles, and that doesn&#39;t work when our design systems are
component-based and not page-based.&lt;/p&gt;
&lt;p&gt;The good news is, the ecosystem is changing, and it&#39;s changing pretty rapidly.
CSS is evolving, and a new era of responsive design is right on the horizon.&lt;/p&gt;
&lt;p&gt;We see this happen about every 10 years. 10 years ago, around 2010-2012, we saw
a huge change with mobile and responsive design, and the emergence of CSS3.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;CSS styles timeline&quot; decoding=&quot;async&quot; height=&quot;211&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/IhVNwOMENjOT2eiIXuMg.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Source: &lt;a href=&quot;https://www.webdesignmuseum.org/web-design-history&quot;&gt;Web Design Museum&lt;/a&gt;.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So it works out that, yet again, the ecosystem is ready for some pretty big
changes to happen to CSS. The engineers at Chrome and across the web platform
are prototyping, speccing, and starting the implementation for the next era of
responsive design.&lt;/p&gt;
&lt;p&gt;These updates include user-preference based media features, container queries,
and media queries for new screen types, such as foldable screens.&lt;/p&gt;
&lt;img alt=&quot;Responsive to the user, container, and form factor&quot; decoding=&quot;async&quot; height=&quot;248&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/3yqBl9BQmGEVzDQU3Ivh.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;responsive-to-the-user&quot;&gt;Responsive to the user &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#responsive-to-the-user&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;New user preference media features, give you the ability to style web
experiences that align with the user&#39;s own specific preferences and needs. This
means that preference media features allow you to adapt your user experiences to
your user&#39;s experiences.&lt;/p&gt;
&lt;p&gt;These user preference media features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefers-contrast&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefers-reduced-transparency&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inverted-colors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;And more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Preference features pick up on the preferences a user has set in their operating
system, and help to build a more robust and personalized web experience,
especially for those with accessibility needs.&lt;/p&gt;
&lt;img alt=&quot;Turning on accessibility preferences in an operating system&quot; decoding=&quot;async&quot; height=&quot;428&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/cGWnoAAwMTU7C3HOfYQl.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;prefers-reduced-motion&quot;&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#prefers-reduced-motion&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Users who have set operating system preferences for &lt;a href=&quot;https://web.dev/prefers-reduced-motion/&quot;&gt;reduced
motion&lt;/a&gt;, are requesting fewer
animations when using their computer in general. Therefore, it&#39;s likely that
they wouldn&#39;t appreciate a flashy intro screen, card flip animation, intricate
loader, or other flashy animations while using the web.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;prefers-reduced-motion&lt;/code&gt; you can design your pages with reduced-motion in
mind, and create a motion-enhanced experience for those who don&#39;t have this
preference set.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/r4z52PPvElemSUJwUCZp.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This card has information on both sides. The baseline reduced-motion experience
is a crossfade to show that information, while the motion-enhanced experience is
a card flip.&lt;/p&gt;
&lt;p&gt;Prefers-reduced-motion shouldn&#39;t mean &amp;quot;no motion&amp;quot;, since motion is so critical
to conveying information online. Instead, provide a solid baseline experience
that guides your users without unnecessary movement, and progressively enhance
that experience for your users without those accessibility needs or preferences.&lt;/p&gt;
&lt;h3 id=&quot;prefers-color-scheme&quot;&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#prefers-color-scheme&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another preference media feature is
&lt;a href=&quot;https://web.dev/prefers-color-scheme&quot;&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/a&gt;. This feature helps
you to customize your UI to the theme which your user prefers. In their
operating system, whether it&#39;s on desktop or mobile, users can set a preference
for light, dark, or auto themes, which change depending on the time of day.&lt;/p&gt;
&lt;p&gt;If you set up your page using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/--*&quot; rel=&quot;noopener&quot;&gt;CSS custom
properties&lt;/a&gt;, swapping
color values is made straightforward. You can quickly update your color theme
values, such as &lt;code&gt;backgroundColor&lt;/code&gt; and &lt;code&gt;textOnPrimary&lt;/code&gt; to dynamically adjust to
the new theme within the media query.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/j6Ru11BsBzCmINZDXKql.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;To make it easier to test some of these preference queries out, you can use
&lt;a href=&quot;https://developer.chrome.com/docs/devtools/rendering/emulate-css/&quot; rel=&quot;noopener&quot;&gt;DevTools for emulation&lt;/a&gt; instead of opening up your system preferences each time.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/ol6pVXJLT44wAkRADAcq.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;designing-for-dark-theme&quot;&gt;Designing for dark theme &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#designing-for-dark-theme&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When designing for a dark theme, it&#39;s not just about inverting background and
text colors or &lt;a href=&quot;https://web.dev/color-scheme/&quot;&gt;dark scrollbars&lt;/a&gt;. There are a few
considerations you might not realize. For example,
you might need to desaturate colors on a dark background to reduce visual
vibration.&lt;/p&gt;
&lt;img alt=&quot;Dont use vibrant, saturated color with dark themes&quot; decoding=&quot;async&quot; height=&quot;640&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 698px) 698px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/tWxjbJ6yYUauQoCsySSX.png?auto=format&amp;w=1396 1396w&quot; width=&quot;698&quot; /&gt;
&lt;p&gt;Instead of using shadows to create depth and draw an element forward, you may
want to use light in the element&#39;s background-color to draw it forward. This is
because shadows won&#39;t be as effective on a dark background.&lt;/p&gt;
&lt;figure&gt;
  &lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/ZiasjYiaPFmJJOkxJBce.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;figcaption&gt;
    &lt;a href=&quot;https://material.io/&quot;&gt;Material design&lt;/a&gt; provides some great guidance on designing for dark themes.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Dark themes not only provide a more customized user experience, but they can
also improve battery life significantly in AMOLED screens. Those are the screens
we&#39;re seeing in newer high-end phones, and they&#39;re becoming increasingly popular
across mobile devices.&lt;/p&gt;
&lt;img alt=&quot;screenshot from the talk that showed this graphic originally&quot; decoding=&quot;async&quot; height=&quot;407&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 720px) 720px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/ZszEdn43lc4ZmcOaGKy4.webp?auto=format&amp;w=1440 1440w&quot; width=&quot;720&quot; /&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.theverge.com/2018/11/8/18076502/google-dark-mode-android-battery-life&quot; rel=&quot;noopener&quot;&gt;2018 Android
study&lt;/a&gt;
on dark themes showed a power draw savings of up to 60%, depending on the screen
brightness and overall user interface. The 60% statistic came from comparing the
Youtube play screen with a paused video at 100% screen brightness using dark
theme for the app UI vs a light theme.&lt;/p&gt;
&lt;p&gt;You should always provide a dark theme experience for your users whenever
possible.&lt;/p&gt;
&lt;h2 id=&quot;responsive-to-the-container&quot;&gt;Responsive to the container &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#responsive-to-the-container&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the most exciting emerging areas in CSS is container queries, also
frequently called element queries. It&#39;s hard to understate what the shift from
page-based responsive design to container-based responsive design will do to
evolve the design ecosystem.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of the powerful abilities that container queries provide. You
can manipulate any of the card element&#39;s styles, including the link list, font
sizes, and overall layout based on its parent container:&lt;/p&gt;
&lt;figure&gt;
&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/fvrxk5kXiif6eFX25BH5.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codepen.io/una/pen/LYbvKpK&quot;&gt;See demo on Codepen&lt;/a&gt; (behind a flag in Canary).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This example shows two identical components with two different container sizes,
both taking up space in a layout created using CSS Grid. Each component fits its
unique space allotment, and styles itself accordingly.&lt;/p&gt;
&lt;p&gt;This amount of flexibility is something that is not possible with media queries
alone.&lt;/p&gt;
&lt;p&gt;Container queries provide a much more dynamic approach to responsive design.
This means that if you put this card component in a sidebar or hero section or
within a grid inside of the main body of a page, the component itself owns its
responsive information and sizes according to the container, not the viewport&lt;/p&gt;
&lt;p&gt;This requires the &lt;code&gt;@container&lt;/code&gt; at-rule This works in a similar way to a media
query with &lt;code&gt;@media&lt;/code&gt;, but instead, &lt;code&gt;@container&lt;/code&gt; queries the parent container for
information rather than the viewport and user agent.&lt;/p&gt;
&lt;div&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;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;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 850px&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;.links&lt;/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;.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-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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;First, set containment on the parent element. And then, write a &lt;code&gt;@container&lt;/code&gt;
query, to style any of the elements within the container based on its size,
using &lt;code&gt;min-width&lt;/code&gt; or &lt;code&gt;max-width&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code above uses &lt;code&gt;max-width&lt;/code&gt;, and sets the links to &lt;code&gt;display:none&lt;/code&gt;, as well
as decreasing the time font size when the container is less than &lt;code&gt;850px&lt;/code&gt; wide.&lt;/p&gt;
&lt;h3 id=&quot;container-query-cards&quot;&gt;Container query cards &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#container-query-cards&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this demo plant website, each of the product cards, including the one in the
hero, the sidebar of recently viewed items, and the product grid, are all the
exact same component, with the same markup.&lt;/p&gt;
&lt;figure&gt;
&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/D4hBchz6kaPjkgx8BCmU.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codepen.io/una/pen/mdOgyVL&quot;&gt;See demo on Codepen&lt;/a&gt; (behind a flag in Canary).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There are &lt;em&gt;no&lt;/em&gt; media queries used to create this entire layout, just container
queries. This allows for each product card to shift to the proper layout to fill
its space. The grid for example, uses a minmax column layout to let the elements
flow into their space, and re-layout the grid when that space is too compressed
(which means that it hit the minimum size).&lt;/p&gt;
&lt;div&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;.product&lt;/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;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 350px&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&lt;/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.5rem 0 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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.card-container 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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When there is at least &lt;code&gt;350px&lt;/code&gt; of space in the grid, the card layout goes
horizontal by being set to &lt;code&gt;display: flex&lt;/code&gt;, which has a default flex-direction
of &amp;quot;row&amp;quot;.&lt;/p&gt;
&lt;p&gt;With less space, the product cards stack. Each product card styles itself,
something that would be impossible with global styles alone.&lt;/p&gt;
&lt;h3 id=&quot;mixing-container-queries-with-media-queries&quot;&gt;Mixing Container Queries with Media Queries &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#mixing-container-queries-with-media-queries&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Container queries have so many use cases—one being a calendar component. You
can use container queries to re-layout the calendar events and other segments
based on the available width of their parent.&lt;/p&gt;
&lt;figure&gt;
&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/hjV6i4PEu8wounYhHsHf.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://codepen.io/una/pen/RwodQZw&quot;&gt;See demo on Codepen&lt;/a&gt; (behind a flag in Canary).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This demo container queries to change the layout and style of the calendar&#39;s
date and day of the week, as well as adjusting the margins and font size on the
scheduled events to help them better fit the space.&lt;/p&gt;
&lt;p&gt;Then, use a media query to shift the entire layout for smaller screen sizes.
This example shows how powerful it is to &lt;em&gt;combine&lt;/em&gt; media queries (adjusting the
global, or macro styles) with container queries (adjusting the container&#39;s
children, and their micro styles).&lt;/p&gt;
&lt;p&gt;So now we can think of Macro and Micro layouts within the same UI component to
allow for some really nice nuanced design decisions.&lt;/p&gt;
&lt;h3 id=&quot;using-container-queries-today&quot;&gt;Using container queries today &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#using-container-queries-today&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These demos are now available to play with behind a flag in Chrome Canary. Go to
&lt;code&gt;about://flags&lt;/code&gt; in Canary and turn on the &lt;code&gt;#enable-container-queries&lt;/code&gt; flag.
This will enable support for &lt;code&gt;@container&lt;/code&gt;, &lt;code&gt;inline-size&lt;/code&gt; and &lt;code&gt;block-size&lt;/code&gt; values
for the &lt;code&gt;contain&lt;/code&gt; property, and the LayoutNG Grid implementation.&lt;/p&gt;
&lt;p&gt;The flag also enables the corresponding Chrome DevTools features.
Learn how to &lt;a href=&quot;https://developer.chrome.com/docs/devtools/css/container-queries/&quot; rel=&quot;noopener&quot;&gt;inspect and debug container queries in DevTools&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scoped-styles&quot;&gt;Scoped styles &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#scoped-styles&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To build on container queries, the CSS working group is also actively discussing
&lt;a href=&quot;https://css.oddbird.net/scope/&quot; rel=&quot;noopener&quot;&gt;scoped styles&lt;/a&gt; to help with proper namespacing
and collision-avoidance for components.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;scoped styles diagram&quot; decoding=&quot;async&quot; height=&quot;636&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 759px) 759px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/FCHIEO4IouHOQaOJXrQD.png?auto=format&amp;w=1518 1518w&quot; width=&quot;759&quot; /&gt;
&lt;figcaption&gt;Figure originally designed by &lt;a href=&quot;https://css.oddbird.net/&quot;&gt;Miriam Suzanne&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Scoped styles allow for pass-through and component-specific styling to avoid
naming collisions, something that many frameworks and plugins like CSS modules
already enable us to do within frameworks. This spec would now allow us to write
encapsulated styles natively for our components with readable CSS without the
need to adjust the markup.&lt;/p&gt;
&lt;div&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;/* @scope (&amp;lt;root&gt;#) [to (&amp;lt;boundary&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;@scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.tabs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; to &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.panel&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;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* targeting the scope root */&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;.light-theme :scope .tab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* contextual styles */&lt;/span&gt; &lt;span 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&gt;&lt;p&gt;Scoping would allow us to create &amp;quot;donut shaped&amp;quot; selectors, where we can specify
where to keep a style encapsulated, and where to break out of that scoped style
to refer back to a more global style.&lt;/p&gt;
&lt;p&gt;An example of this would be a tab panel, where we&#39;d want the tabs to get the
scoped style, and the panel within the tabs to get a parent style.&lt;/p&gt;
&lt;h2 id=&quot;responsive-to-the-form-factor&quot;&gt;Responsive to the form factor &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#responsive-to-the-form-factor&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next topic in our conversation about the new era of responsive design is a
shift in form factors, and the growing possibilities of what we&#39;ll need to be
designing for as a web community (such as shape-shifting screen or virtual
reality).&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Spanning diagram&quot; decoding=&quot;async&quot; height=&quot;488&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/OeskptFb2djUWWmX7K9y.svg&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;Diagram from &lt;a href=&quot;https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md&quot;&gt;Microsoft Edge Explainers&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Foldable or flexible screens, and designing for screen spanning is one example
of where we can see a form factor shift today. And screen-spanning is yet
another spec being worked on to cover these new form factors and needs.&lt;/p&gt;
&lt;p&gt;An experimental &lt;a href=&quot;https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md&quot; rel=&quot;noopener&quot;&gt;media
query&lt;/a&gt;
for screen-spanning could help us here. It currently behaves like this: &lt;code&gt;@media (spanning: &amp;lt;type of fold&amp;gt;)&lt;/code&gt;. The demo sets up a grid layout with two columns:
one has a width of --sidebar-width, which is 5rem by default, and the other is
&lt;code&gt;1fr&lt;/code&gt;. When the layout is viewed on a dual screen that has a single vertical
fold, the value of &lt;code&gt;--sidebar-width&lt;/code&gt; is updated with the environment value of
the left fold.&lt;/p&gt;
&lt;div&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;--sidebar-width&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;&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;spanning&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; single-fold-vertical&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;--sidebar-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fold-left&lt;span class=&quot;token punctuation&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;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;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--sidebar-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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This enables a layout where the sidebar, the navigation in this case, fills the
space of one of the folds, where the app UI fills the other. This prevents a
&amp;quot;crease&amp;quot; in the UI.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/HodOHWjMnbNw56hvNASHWSgZyAf2/Uf3RL7EhVZGK2ECiD0sT.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;You can test out foldable screens in the Chrome DevTools emulator to help debug
and prototype screen spanning directly in the browser.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Exploring UI design beyond a flat screen is yet another reason why container
queries and scoped styles are so important. They give you the opportunity to
silo component styles from page layout and global styles, and user styles,
enabling more resilient responsive design. This means you can now design macro
layouts using page-based media queries, including screen-spanning nuances. At
the same time using micro layouts with container queries on the components, and
add user-preference based media queries to customize user experiences based on
their unique preferences and need.&lt;/p&gt;
&lt;img alt=&quot;A circle of the new responsive&quot; decoding=&quot;async&quot; height=&quot;442&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/HodOHWjMnbNw56hvNASHWSgZyAf2/uAJDDUDLcAsLzBf0a27b.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;This&lt;/em&gt; is the new responsive.&lt;/p&gt;
&lt;p&gt;It&#39;s combining macro layout with micro layout, and on top of all of that, it&#39;s
taking user customization and form factor into account.&lt;/p&gt;
&lt;p&gt;Any of these changes alone would constitute a considerable shift in how we
design for the web. But combined, they signify a really big shift in how we even
conceptualize responsive design. It&#39;s time to think about responsive design
beyond viewport size, and start considering all of these new axes for better
component-based and customized experiences.&lt;/p&gt;
&lt;p&gt;The next era of responsive design is here, and you can already start to
explore it yourself.&lt;/p&gt;
&lt;h3 id=&quot;webdevlearncss&quot;&gt;web.dev/learnCSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/new-responsive/#webdevlearncss&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;And for now, if you want to level up your CSS game, and maybe revisit some
basics, my team is launching a brand new, totally free CSS course and reference
on web.dev. You can access it via &lt;a href=&quot;https://web.dev/learn/css&quot;&gt;web.dev/learnCSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed this overview on the next era of responsive design, and some
of the primitives that will come along with it, and I also hope you&#39;re as
excited as I am about what this means for the future of web design.&lt;/p&gt;
&lt;p&gt;It opens up a huge opportunity to us as a UI community to embrace
component-based styles, new form factors, and create user-responsive
experiences.&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>New aspect-ratio CSS property supported in Chromium, Safari Technology Preview, and Firefox Nightly</title>
    <link href="https://web.dev/aspect-ratio/"/>
    <updated>2021-01-28T00:00:00Z</updated>
    <id>https://web.dev/aspect-ratio/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  Summary: Maintaining a consistent width-to-height ratio, called an &lt;em&gt;aspect ratio&lt;/em&gt;, is critical in responsive web design and for preventing &lt;a href=&quot;https://web.dev/cls/&quot;&gt;cumulative layout shift&lt;/a&gt;. Now, there&#39;s a more straightforward way to do this with the new &lt;code&gt;aspect-ratio&lt;/code&gt; property launching in &lt;a href=&quot;https://www.chromestatus.com/feature/5738050678161408&quot;&gt;Chromium 88&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Experimental_features#property_aspect-ratio&quot;&gt;Firefox 87&lt;/a&gt;, and &lt;a href=&quot;https://developer.apple.com/safari/technology-preview/release-notes/&quot;&gt;Safari Technology Preview 118&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;aspect-ratio&quot;&gt;Aspect ratio &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#aspect-ratio&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 88, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      88
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 89, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      89
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 88, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      88
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 15, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      15
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/aspect-ratio#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Aspect ratio is most commonly expressed as two integers and a colon in the dimensions of:
width:height, or x:y. The most common aspect ratios for photography are 4:3 and 3:2, while video,
and more recent consumer cameras, tend to have a 16:9 aspect ratio.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Two images with the same aspect ratio. One is 634 x 951px while the other is 200 x 300px. Both have a 2:3 aspect ratio.&quot; decoding=&quot;async&quot; height=&quot;526&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/od54hUUe21UABpbWxSFG.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Two images with the same aspect ratio. One is 634 x 951px while the other is 200 x 300px. Both have a 2:3 aspect ratio.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;With the advent of responsive design, maintaining aspect ratio has been increasingly important for
web developers, especially as image dimensions differ and element sizes shift based on available
space.&lt;/p&gt;
&lt;p&gt;Some examples of where maintaining aspect ratio become important are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating responsive iframes, where they are 100% of a parent&#39;s width, and the height should remain
a specific viewport ratio&lt;/li&gt;
&lt;li&gt;Creating intrinsic placeholder containers for images, &lt;a href=&quot;http://fitvidsjs.com/&quot; rel=&quot;noopener&quot;&gt;videos&lt;/a&gt;, and embeds
to prevent re-layout when the items load and take up space&lt;/li&gt;
&lt;li&gt;Creating uniform, responsive space for interactive data visualizations or SVG animations&lt;/li&gt;
&lt;li&gt;Creating uniform, responsive space for multi-element components such as cards or calendar dates&lt;/li&gt;
&lt;li&gt;Creating uniform, responsive space for multiple images of varying dimension (can be used alongside
&lt;code&gt;object-fit&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;object-fit&quot;&gt;Object-fit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#object-fit&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Defining an aspect ratio helps us with sizing media in a responsive context. Another tool in this
bucket is the &lt;code&gt;object-fit&lt;/code&gt; property, which enables users to describe how an object (such an as image)
within a block should fill that block:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Object-fit demo visualization&quot; decoding=&quot;async&quot; height=&quot;236&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/A7uj6u5MULodlw4lVsI2.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Showcasing various &lt;code&gt;object-fit&lt;/code&gt; values. See &lt;a href=&quot;https://codepen.io/una/pen/mdrLGjR&quot;&gt;demo on Codepen&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;initial&lt;/code&gt; and &lt;code&gt;fill&lt;/code&gt; values re-adjust the image to fill the space. In our example, this causes
the image to be squished and blurry, as it re-adjusts pixels. Not ideal. &lt;code&gt;object-fit: cover&lt;/code&gt; uses
the image&#39;s smallest dimension to fill the space and crops the image to fit into it based on this
dimension. It &amp;quot;zooms in&amp;quot; at its lowest boundary. &lt;code&gt;object-fit: contain&lt;/code&gt; ensures that the entire image
is always visible, and so the opposite of &lt;code&gt;cover&lt;/code&gt;, where it takes the size of the largest boundary
(in our example above this is width), and resizes the image to maintain its intrinsic aspect ratio
while fitting into the space. The &lt;code&gt;object-fit: none&lt;/code&gt; case shows the image cropped in its center
(default object position) at its natural size.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;object-fit: cover&lt;/code&gt; tends to work in most situations to ensure a nice uniform interface when dealing
with images of varying dimensions, however, you lose information this way (the image is cropped at
its longest edges).&lt;/p&gt;
&lt;p&gt;If these details are important (for example, when working with a flat lay of beauty products),
cropping important content is not acceptable. So the ideal scenario would be responsive images of
varying sizes that fit the UI space without cropping.&lt;/p&gt;
&lt;h2 id=&quot;the-old-hack-maintaining-aspect-ratio-with-padding-top&quot;&gt;The old hack: maintaining aspect ratio with &lt;code&gt;padding-top&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#the-old-hack-maintaining-aspect-ratio-with-padding-top&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Using padding-top to set a 1:1 aspect ratio on post preview images within a carousel.&quot; decoding=&quot;async&quot; height=&quot;296&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/j3YJicINXjly349uEEUt.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt; Using &lt;code&gt;padding-top&lt;/code&gt; to set a 1:1 aspect ratio on post preview images within a carousel.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In order to make these more responsive, we can use aspect ratio. This allows for us to set a
specific ratio size and base the rest of the media on an individual axis (height or width).&lt;/p&gt;
&lt;p&gt;A currently well-accepted cross-browser solution for maintaining aspect ratio based on an image&#39;s
width is known as the &amp;quot;Padding-Top Hack&amp;quot;. This solution requires a parent container and an
absolutely placed child container. One would then calculate the aspect ratio as a percentage to set
as the &lt;code&gt;padding-top&lt;/code&gt;. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1:1 aspect ratio = 1 / 1 = 1 = &lt;code&gt;padding-top: 100%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;4:3 aspect ratio = 3 / 4 = 0.75 = &lt;code&gt;padding-top: 75%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;3:2 aspect ratio = 2 / 3 = 0.66666 = &lt;code&gt;padding-top: 66.67%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;16:9 aspect ratio = 9 / 16 = 0.5625 = &lt;code&gt;padding-top: 56.25%&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have identified the aspect ratio value, we can apply that to our parent container.
Consider the following example:&lt;/p&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;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&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;media&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;...&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We could then write the following CSS:&lt;/p&gt;
&lt;div&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;.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;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 property&quot;&gt;padding-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 56.25%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* 16:9 Aspect Ratio */&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;.media&lt;/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; 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;/div&gt;&lt;h2 id=&quot;maintaining-aspect-ratio-with-aspect-ratio&quot;&gt;Maintaining aspect ratio with &lt;code&gt;aspect-ratio&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#maintaining-aspect-ratio-with-aspect-ratio&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Using aspect-ratio to set a 1:1 aspect ratio on post preview images within a carousel.&quot; decoding=&quot;async&quot; height=&quot;296&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/XT8PbPiYx1IJq3Pvmanz.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Using &lt;code&gt;aspect-ratio&lt;/code&gt; to set a 1:1 aspect ratio on post preview images within a carousel.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Unfortunately, calculating these &lt;code&gt;padding-top&lt;/code&gt; values is not very intuitive, and requires some
additional overhead and positioning. With the new intrinsic &lt;code&gt;aspect-ratio&lt;/code&gt; &lt;a href=&quot;https://drafts.csswg.org/css-sizing-4/#aspect-ratio&quot; rel=&quot;noopener&quot;&gt;CSS
property&lt;/a&gt;, the language for maintaining aspect
ratios is much more clear.&lt;/p&gt;
&lt;p&gt;With the same markup, we can replace: &lt;code&gt;padding-top: 56.25%&lt;/code&gt; with &lt;code&gt;aspect-ratio: 16 / 9&lt;/code&gt;, setting
&lt;code&gt;aspect-ratio&lt;/code&gt; to a specified ratio of &lt;code&gt;width&lt;/code&gt; / &lt;code&gt;height&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;switcher&quot;&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Using padding-top&lt;/p&gt;
&lt;div&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;.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;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;padding-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 56.25%&lt;span 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&gt;&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Using aspect-ratio&lt;/p&gt;
&lt;div&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;.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;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; 16 / 9&lt;span 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&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;aspect-ratio&lt;/code&gt; instead of &lt;code&gt;padding-top&lt;/code&gt; is much more clear, and does not overhaul the padding
property to do something outside of its usual scope.&lt;/p&gt;
&lt;p&gt;This new property also adds the ability to
set aspect ratio to &lt;code&gt;auto&lt;/code&gt;, where &amp;quot;replaced elements with an intrinsic aspect ratio use that aspect
ratio; otherwise the box has no preferred aspect ratio.&amp;quot; If both &lt;code&gt;auto&lt;/code&gt; and a &lt;code&gt;&amp;lt;ratio&amp;gt;&lt;/code&gt; are
specified together, the preferred aspect ratio is the specified ratio of &lt;code&gt;width&lt;/code&gt; divided by &lt;code&gt;height&lt;/code&gt; unless
it is a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/Replaced_element&quot; rel=&quot;noopener&quot;&gt;replaced element&lt;/a&gt; with
an intrinsic aspect ratio, in which case that aspect ratio is used instead.&lt;/p&gt;
&lt;h2 id=&quot;example-consistency-in-a-grid&quot;&gt;Example: consistency in a grid &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#example-consistency-in-a-grid&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This works really well with CSS layout mechanisms like CSS Grid and Flexbox as well. Consider a list
with children that you want to maintain a 1:1 aspect ratio, such as a grid of sponsor icons:&lt;/p&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;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;sponsor-grid&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 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;sponsor&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;...&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;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 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;sponsor&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;...&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;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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div&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;.sponsor-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; 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-fill&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;120px&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.sponsor 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 / 1&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;object-fit&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/aspect-ratio/gridimages2.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Images in a grid with their parent element at various aspect ratio dimensions. &lt;a href=&quot;https://codepen.io/una/pen/PoGddaw&quot;&gt;See demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;example-preventing-layout-shift&quot;&gt;Example: preventing layout shift &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#example-preventing-layout-shift&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another great feature of &lt;code&gt;aspect-ratio&lt;/code&gt; is that it can create placeholder space to prevent
&lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift&lt;/a&gt; and deliver better &lt;a href=&quot;https://web.dev/learn-core-web-vitals/&quot;&gt;Web Vitals&lt;/a&gt;. In this first
example, loading an asset from an API such as &lt;a href=&quot;https://source.unsplash.com/&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt; creates a
layout shift when the media is finished loading.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/aspect-ratio/aspect-ratio-missing.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Video of cumulative layout shift that happens when no aspect ratio is set on a loaded asset. This video is recorded with an emulated 3G network.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Using &lt;code&gt;aspect-ratio&lt;/code&gt;, on the other hand, creates a placeholder to prevent this layout shift:&lt;/p&gt;
&lt;div&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;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;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; 8 / 6&lt;span 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&gt;&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/aspect-ratio/aspect-ratio-set.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Video with a set aspect ratio is set on a loaded asset. This video is recorded with an emulated 3G network. &lt;a href=&quot;https://codepen.io/una/pen/GRjLZmG&quot;&gt;See demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;bonus-tip-image-attributes-for-aspect-ratio&quot;&gt;Bonus tip: image attributes for aspect ratio &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#bonus-tip-image-attributes-for-aspect-ratio&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another way to set an image&#39;s aspect ratio is through &lt;a href=&quot;https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/&quot; rel=&quot;noopener&quot;&gt;image attributes&lt;/a&gt;. If you know the dimensions of the image ahead of time, it is a &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/image-aspect-ratio/#check-the-images-width-and-height-attributes-in-the-html&quot; rel=&quot;noopener&quot;&gt;best practice&lt;/a&gt; to
set these dimensions as its &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For our example above, knowing the dimensions are 800px by 600px, the image markup would look like: &lt;code&gt;&amp;lt;img src=&amp;quot;image.jpg&amp;quot; alt=&amp;quot;...&amp;quot; width=&amp;quot;800&amp;quot; height=&amp;quot;600&amp;quot;&amp;gt;&lt;/code&gt;. If the image sent has the same aspect
ratio, but not necessarily those exact pixel values, we could still use image
attribute values to set the ratio, combined with a style of &lt;code&gt;width: 100%&lt;/code&gt; so
that the image takes up the proper space. All together that would look like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Markup --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;8&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;6&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;/div&gt;&lt;div&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;/* CSS */&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;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;/div&gt;&lt;p&gt;In the end, the effect is the same as setting the &lt;code&gt;aspect-ratio&lt;/code&gt; on the
image via CSS, and cumulative layout shift is avoided (&lt;a href=&quot;https://codepen.io/una/pen/gOwJWoz&quot; rel=&quot;noopener&quot;&gt;see demo on
Codepen&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/aspect-ratio/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the new &lt;code&gt;aspect-ratio&lt;/code&gt; CSS property, launching across multiple modern browsers, maintaining proper
aspect ratios in your media and layout containers gets a little bit more straightforward.&lt;/p&gt;
&lt;p&gt;Photos by &lt;a href=&quot;https://unsplash.com/photos/TXg_38oImi0&quot; rel=&quot;noopener&quot;&gt;Amy Shamblen&lt;/a&gt; and &lt;a href=&quot;https://unsplash.com/photos/c1rOy44wuts&quot; rel=&quot;noopener&quot;&gt;Lionel
Gustave&lt;/a&gt; via Unsplash.&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>Cross-browser paint worklets and Houdini.how</title>
    <link href="https://web.dev/houdini-how/"/>
    <updated>2020-12-10T00:00:00Z</updated>
    <id>https://web.dev/houdini-how/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;5eBar5TI71M&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;CSS &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Houdini&quot; rel=&quot;noopener&quot;&gt;Houdini&lt;/a&gt; is an umbrella term that
describes a series of low-level browser APIs that give developers much more control and power over
the styles they write.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Houdini layer&quot; decoding=&quot;async&quot; height=&quot;599&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/KgTxiRodgp6kFwHGHvqA.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Houdini enables more semantic CSS with the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CSS_Typed_OM_API/Guide&quot; rel=&quot;noopener&quot;&gt;Typed Object
Model&lt;/a&gt;. Developers can
define advanced CSS custom properties with syntax, default values, and inheritance through the
&lt;a href=&quot;https://web.dev/at-property/&quot;&gt;Properties and Values API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It also introduces paint, layout, and animation
&lt;a href=&quot;https://developer.chrome.com/blog/animation-worklet&quot; rel=&quot;noopener&quot;&gt;worklets&lt;/a&gt;, which open up a
world of possibilities, by making it easier for authors to hook into the styling and layout process
of the browser&#39;s rendering engine.&lt;/p&gt;
&lt;h2 id=&quot;understanding-houdini-worklets&quot;&gt;Understanding Houdini worklets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#understanding-houdini-worklets&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Houdini worklets are browser instructions that run off the main thread and can be called when
needed. Worklets enable you to write modular CSS to accomplish specific tasks, and require a single
line of JavaScript to import and register. Much like service workers for CSS style, Houdini worklets
are registered to your application, and once registered can be used in your CSS by name.&lt;/p&gt;
&lt;p&gt;Write worklet file Register worklet module (&lt;code&gt;CSS.paintWorklet.addModule(workletURL)&lt;/code&gt;) Use worklet
(&lt;code&gt;background: paint(confetti)&lt;/code&gt;)&lt;/p&gt;
&lt;h2 id=&quot;implementing-your-own-features-with-the-css-painting-api&quot;&gt;Implementing your own features with the CSS Painting API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#implementing-your-own-features-with-the-css-painting-api&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://drafts.css-houdini.org/css-paint-api/&quot; rel=&quot;noopener&quot;&gt;CSS Painting API&lt;/a&gt; is an example of such a
worklet (the Paint worklet), and enables developers to define canvas-like custom painting functions
that can be used directly in CSS as backgrounds, borders, masks, and more. There is a whole world of
possibilities for how you can use CSS Paint in your own user interfaces.&lt;/p&gt;
&lt;p&gt;For example, instead of waiting for a browser to implement an angled borders feature, you can write
your own Paint worklet, or use an existing published worklet. Then, rather than using border-radius
apply this worklet to borders and clipping.&lt;/p&gt;
&lt;figure&gt;
  &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/LNMysDPgN7nSgyT1p1Fl.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    The example above uses the same paint worklet with different arguments (see code below) to accomplish this result. Demo on &lt;a href=&quot;https://glitch.com/~angled-corners&quot;&gt;Glitch&lt;/a&gt;.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div&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;.angled&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--corner-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 15 0 0 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--paint-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #6200ee&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stroke-weight&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;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Mask every angled button with fill mode */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;-webkit-mask&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;angled-corners&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; filled&lt;span class=&quot;token punctuation&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;.outline&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stroke-weight&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 comment&quot;&gt;/* Paint outline */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-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;angled-corners&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outlined&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 0 fill &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;/div&gt;&lt;p&gt;The CSS Painting API is currently one of the best-supported Houdini APIs, its spec being a W3C
candidate recommendation. It is currently enabled in all Chromium-based browsers, partially
supported in Safari, and is under consideration for Firefox.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Caniuse support&quot; decoding=&quot;async&quot; height=&quot;176&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/vL8Z5YEwk2g2QJ6T6IWp.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;The CSS Painting API is currently supported on Chromium-based browsers.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;But even without full browser support, you can still get creative with the Houdini Paint API and see
your styles work across all modern browsers with the &lt;a href=&quot;https://github.com/GoogleChromeLabs/css-paint-polyfill&quot; rel=&quot;noopener&quot;&gt;CSS Paint
Polyfill&lt;/a&gt;. And to showcase a few unique
implementations, as well as to provide a resource and worklet library, my team built
&lt;a href=&quot;https://houdini.how/&quot; rel=&quot;noopener&quot;&gt;houdini.how&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;houdinihow&quot;&gt;Houdini.how &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#houdinihow&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Worklet page screenshot.&quot; decoding=&quot;async&quot; height=&quot;833&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/UKenhKMvDWI9PvWGcTG4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the &lt;a href=&quot;https://houdini.how/&quot;&gt;Houdini.how&lt;/a&gt; homepage.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://houdini.how/&quot; rel=&quot;noopener&quot;&gt;Houdini.how&lt;/a&gt; is a library and reference for Houdini worklets and resources. It
provides everything you need to know about CSS Houdini: browser support, an
&lt;a href=&quot;https://houdini.how/about&quot; rel=&quot;noopener&quot;&gt;overview&lt;/a&gt; of its various APIs, &lt;a href=&quot;https://houdini.how/usage&quot; rel=&quot;noopener&quot;&gt;usage&lt;/a&gt;
information, additional &lt;a href=&quot;https://houdini.how/resources&quot; rel=&quot;noopener&quot;&gt;resources&lt;/a&gt;, and live paint worklet
&lt;a href=&quot;https://houdini.how/&quot; rel=&quot;noopener&quot;&gt;samples&lt;/a&gt;. Each sample on Houdini.how is backed by the CSS Paint API, meaning
they each work on all modern browsers. Give it a whirl!&lt;/p&gt;
&lt;h2 id=&quot;using-houdini&quot;&gt;Using Houdini &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#using-houdini&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Houdini worklets must either be run via a server locally, or on HTTPS in production. In order to
work with a Houdini worklet, you will need to either install it locally or use a content delivery
network (CDN) like &lt;a href=&quot;https://unpkg.com/&quot; rel=&quot;noopener&quot;&gt;unpkg&lt;/a&gt; to serve the files. You will then need to register the
worklet locally.&lt;/p&gt;
&lt;p&gt;There are a few ways to include the Houdini.how showcase worklets in your own web projects. They can
either be used via a CDN in a prototyping capacity, or you can manage the worklets on your own using
npm modules. Either way, you&#39;ll want to also include the CSS Paint Polyfill to ensure they are
cross-browser compatible.&lt;/p&gt;
&lt;h3 id=&quot;1-prototyping-with-a-cdn&quot;&gt;1. Prototyping with a CDN &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#1-prototyping-with-a-cdn&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When registering from unpkg, you can link directly to the worklet.js file without needing to locally
install the worklet. Unpkg will resolve to the worklet.js as the main script, or you can specify it
yourself. Unpkg will not cause CORS issues, as it is served over HTTPS.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;CSS.paintWorklet.addModule(&quot;https://unpkg.com/&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;package-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Note that this does not register the custom properties for syntax and fallback values. Instead, they
each have fallback values embedded into the worklet.&lt;/p&gt;
&lt;p&gt;To optionally register the custom properties, include the properties.js file as well.&lt;/p&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;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/&amp;lt;package-name&gt;/properties.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 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&gt;&lt;p&gt;To include the CSS Paint Polyfill with unpkg:&lt;/p&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;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;/div&gt;&lt;h3 id=&quot;2-managing-worklets-via-npm&quot;&gt;2. Managing worklets via NPM &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#2-managing-worklets-via-npm&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install your worklet from npm:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;package-name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; css-paint-polyfill&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Importing this package does not automatically inject the paint worklet. To install the worklet,
you&#39;ll need to generate a URL that resolves to the package&#39;s worklet.js, and register that. You do
so with:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&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 punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;file&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;path&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;worklet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The npm package name and link can be found on each worklet card.&lt;/p&gt;
&lt;p&gt;You will also need to include the CSS Paint Polyfill via script or import it directly, as you would
with a framework or bundler.&lt;/p&gt;
&lt;p&gt;Here is an example of how to use Houdini with the paint polyfill in modern bundlers:&lt;/p&gt;
&lt;div&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 string&quot;&gt;&#39;css-paint-polyfill&#39;&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 string&quot;&gt;&#39;&amp;lt;package-name&gt;/properties.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// optionally register properties&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; workletURL &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;url:&amp;lt;package-name&gt;/worklet.js&#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 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;workletURL&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&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; For more specific instruction per-bundler, check out the &lt;a href=&quot;https://houdini.how/usage&quot;&gt;usage page&lt;/a&gt; on Houdini.how. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;contribute&quot;&gt;Contribute &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/houdini-how/#contribute&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;ve played around with some Houdini samples, it&#39;s your turn to contribute your own!
Houdini.how does not host any worklets itself, and instead showcases the work of the community. If
you have a worklet or resource you would like to submit, check out the &lt;a href=&quot;https://github.com/GoogleChromeLabs/houdini.how/blob/main/CONTRIBUTING.md&quot; rel=&quot;noopener&quot;&gt;github
repo&lt;/a&gt; with contribution guidelines.
We&#39;d love to see what you come up with!&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>min(), max(), and clamp(): three logical CSS functions to use today</title>
    <link href="https://web.dev/min-max-clamp/"/>
    <updated>2020-10-14T00:00:00Z</updated>
    <id>https://web.dev/min-max-clamp/</id>
    <content type="html" mode="escaped">&lt;p&gt;With responsive design evolving and becoming increasingly nuanced, CSS itself is
constantly evolving and providing authors increased control. The
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/min&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;min()&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/max&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;max()&lt;/code&gt;&lt;/a&gt;, and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/clamp&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;clamp()&lt;/code&gt;&lt;/a&gt; functions,
now supported in all modern browsers, are among the latest tools in making
authoring websites and apps more dynamic and responsive.&lt;/p&gt;
&lt;p&gt;When it comes to flexible and fluid typography, controlled element resizing, and
maintaining proper spacing, &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, and &lt;code&gt;clamp()&lt;/code&gt; can help.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#background&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;The math functions, &lt;code&gt;calc()&lt;/code&gt;, &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, and &lt;code&gt;clamp()&lt;/code&gt; allow mathematical expressions with addition (+), subtraction (-), multiplication (*), and division (/) to be used as component values&lt;/p&gt;
  &lt;cite&gt;&lt;a href=&quot;https://www.w3.org/TR/css-values-4/#calc-notation&quot;&gt;CSS Values And Units Level 4&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser support &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#browser-support&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;min&quot;&gt;&lt;code&gt;min()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#min&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 75, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      75
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 11.1, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      11.1
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/min#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h3 id=&quot;max&quot;&gt;&lt;code&gt;max()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#max&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 75, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      75
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 11.1, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      11.1
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/max#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h3 id=&quot;clamp&quot;&gt;&lt;code&gt;clamp()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#clamp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 75, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      75
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 13.1, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      13.1
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/clamp#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#usage&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/min-demo.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Showing how the min() function selects a value based on a list of options and its parent. &lt;a href=&quot;https://codepen.io/una/pen/rNeGNVL&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can use &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, and &lt;code&gt;clamp()&lt;/code&gt; on the right hand side of any CSS
expression where it would make sense. For &lt;code&gt;min()&lt;/code&gt; and &lt;code&gt;max()&lt;/code&gt;, you provide an
argument list of values, and the browser determines which one is either the
smallest or largest, respectively. For example, in the case of: &lt;code&gt;min(1rem, 50%, 10vw)&lt;/code&gt;, the browser calculates which of these relative units is the smallest,
and uses that value as the actual value.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/max-demo.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Showing how the max() function selects a value based on a list of options and its parent. &lt;a href=&quot;https://codepen.io/una/pen/RwaZXqR&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;max()&lt;/code&gt; function selects the largest value from a list of comma-separated
expressions.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/clamp-demo.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Showing how the clamp() function selects a value based on a list of options and its parent. &lt;a href=&quot;https://codepen.io/una/pen/bGpoGdJ&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To use &lt;code&gt;clamp()&lt;/code&gt; enter three values: a minimum value, ideal value (from which to
calculate), and maximum value.&lt;/p&gt;
&lt;p&gt;Any of these functions can be used anywhere a &lt;code&gt;&amp;lt;length&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;frequency&amp;gt;&lt;/code&gt;,
&lt;code&gt;&amp;lt;angle&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;percentage&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;integer&amp;gt;&lt;/code&gt; is allowed. You
can use these on their own (i.e. &lt;code&gt;font-size: max(0.5vw, 50%, 2rem)&lt;/code&gt;), in
conjunction with &lt;code&gt;calc()&lt;/code&gt; (i.e. &lt;code&gt;font-size: max(calc(0.5vw - 1em), 2rem)&lt;/code&gt;), or
composed (i.e. &lt;code&gt;font-size: max(min(0.5vw, 1em), 2rem)&lt;/code&gt;).&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; When using a calculation inside of a &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, or &lt;code&gt;clamp()&lt;/code&gt; function, you can remove the call to &lt;code&gt;calc()&lt;/code&gt;. For example, writing &lt;code&gt;font-size: max(calc(0.5vw - 1em), 2rem)&lt;/code&gt; would be the same as &lt;code&gt;font-size: max(0.5vw - 1em, 2rem)&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;To recap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;min(&amp;lt;value-list&amp;gt;)&lt;/code&gt;: selects the smallest (most negative) value from a list of
comma-separated expressions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max(&amp;lt;value-list&amp;gt;)&lt;/code&gt;: selects the largest (most positive) value from a list of
comma-separated expressions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clamp(&amp;lt;min&amp;gt;, &amp;lt;ideal&amp;gt;, &amp;lt;max&amp;gt;)&lt;/code&gt;: clamps a value between an upper and lower
bound, based on a set ideal value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&#39;s take a look at some examples.&lt;/p&gt;
&lt;h2 id=&quot;the-perfect-width&quot;&gt;The perfect width &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#the-perfect-width&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;According to &lt;a href=&quot;http://webtypography.net/2.1.2#:~:text=%E2%80%9CAnything%20from%2045%20to%2075,is%2040%20to%2050%20characters.%E2%80%9D&quot; rel=&quot;noopener&quot;&gt;The Elements of Typographic
Style&lt;/a&gt;
by Robert Bringhurst, &amp;quot;anything from 45 to 75 characters is widely regarded as a
satisfactory length of line for a single-column page set in a serifed text face
in a text size.&amp;quot;&lt;/p&gt;
&lt;p&gt;To ensure that your text blocks are not narrower than 45 characters or wider
than 75 characters, use &lt;code&gt;clamp()&lt;/code&gt; and the &lt;code&gt;ch&lt;/code&gt; (0-width &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/length&quot; rel=&quot;noopener&quot;&gt;character advance&lt;/a&gt;)
unit:&lt;/p&gt;
&lt;div&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;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;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;45ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 75ch&lt;span class=&quot;token punctuation&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&gt;&lt;p&gt;This allows for the browser to determine the width of the paragraph. It will set
the width to 50%, unless 50% is smaller than &lt;code&gt;45ch&lt;/code&gt;, at which point &lt;code&gt;45ch&lt;/code&gt; will
be selected, and visa versa for if 50% is wider than &lt;code&gt;75ch&lt;/code&gt;. In this demo, the
card itself is getting clamped:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/clamp-width.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Using the clamp() function to limit a minimum and maximum width. &lt;a href=&quot;https://codepen.io/una/pen/QWyLxaL&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You could break this up with just the &lt;code&gt;min()&lt;/code&gt; or &lt;code&gt;max()&lt;/code&gt; function. If you want
the element to always be at &lt;code&gt;50%&lt;/code&gt; width, and not exceed &lt;code&gt;75ch&lt;/code&gt; in width (i.e. on
larger screens), write: &lt;code&gt;width: min(75ch, 50%);&lt;/code&gt;. This essentially sets a &amp;quot;max&amp;quot;
size by using the &lt;code&gt;min()&lt;/code&gt; function.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/min-width.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Using the min() function to set a maximum width.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;By the same token, you can ensure a minimum size for legible text using the
&lt;code&gt;max()&lt;/code&gt; function. This would look like: &lt;code&gt;width: max(45ch, 50%);&lt;/code&gt;. Here, the
browser selects whichever is larger, &lt;code&gt;45ch&lt;/code&gt; or &lt;code&gt;50%&lt;/code&gt;, meaning the element must
be at &lt;em&gt;least&lt;/em&gt; &lt;code&gt;45ch&lt;/code&gt; or larger.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/max-width.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Using the max() function to set a minimum width.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;padding-management&quot;&gt;Padding management &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#padding-management&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using the same concept as above, where the &lt;code&gt;min()&lt;/code&gt; function can set a &amp;quot;max&amp;quot;
value and &lt;code&gt;max()&lt;/code&gt; sets a &amp;quot;min&amp;quot; value, you can use &lt;code&gt;max()&lt;/code&gt; to set a minimum
padding size. This example comes from &lt;a href=&quot;https://css-tricks.com/using-max-for-an-inner-element-max-width/&quot; rel=&quot;noopener&quot;&gt;CSS
Tricks&lt;/a&gt;, where
reader Caluã de Lacerda Pataca shared this idea: The idea is to enable an
element to have additional padding at larger screen sizes, but maintain a
minimum padding at smaller screen sizes, particularly on the inline padding. To
achieve this, use &lt;code&gt;calc()&lt;/code&gt; and subtract the minimum padding from either side:
&lt;code&gt;calc((100vw - var(--contentWidth)) / 2)&lt;/code&gt;, &lt;em&gt;or&lt;/em&gt; use max: &lt;code&gt;max(2rem, 50vw - var(--contentWidth) / 2)&lt;/code&gt;. All together it looks like:&lt;/p&gt;
&lt;div&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;footer&lt;/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;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--blockPadding&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;2rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50vw - &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--contentWidth&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; / 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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/min-padding.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Setting a minimum padding for a component using the max() function. &lt;a href=&quot;https://codepen.io/chriscoyier/pen/qBZqNKa&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;fluid-typography&quot;&gt;Fluid typography &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#fluid-typography&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to enable &lt;a href=&quot;https://www.smashingmagazine.com/2016/05/fluid-typography/&quot; rel=&quot;noopener&quot;&gt;fluid
typography&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mikeriethmuller&quot; rel=&quot;noopener&quot;&gt;Mike
Riethmeuller&lt;/a&gt; popularized a technique that
uses the &lt;code&gt;clamp()&lt;/code&gt; function to set a minimum font size, maximum font size, and
allow for scaling from the min to the max.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/min-max-clamp/fliud-type.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Creating fluid typography with clamp(). &lt;a href=&quot;https://codepen.io/una/pen/ExyYXaN&quot;&gt;See Demo on Codepen.&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;With &lt;code&gt;clamp()&lt;/code&gt;, you can write this more clearly. Rather than requiring a complex
string, the browser can do the work for you. Set the minimum acceptable font
size (for example, &lt;code&gt;1.5rem&lt;/code&gt; for a title, maximum size (i.e. &lt;code&gt;3rem&lt;/code&gt;) and ideal
size of &lt;code&gt;5vw&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, we get typography that scales with the viewport width of the page until it
reaches the limiting minimum and maximum values, in a much more succinct line of
code:&lt;/p&gt;
&lt;div&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;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.5rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 5vw&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-warn-bg color-state-warn-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block color-state-warn-text&quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Warning sign&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M23 21L12 2 1 21h22zm-12-3v-2h2v2h-2zm0-4h2v-4h-2v4z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Limiting how large text can get with &lt;code&gt;max()&lt;/code&gt; or &lt;code&gt;clamp()&lt;/code&gt; can cause a WCAG failure under &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/quickref/?showtechniques=144#resize-text&quot;&gt;1.4.4 Resize text (AA)&lt;/a&gt; , because a user may be unable to scale the text to 200% of its original size. Be certain to &lt;a href=&quot;https://adrianroselli.com/2019/12/responsive-type-and-zoom.html&quot;&gt;test the results with zoom&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/min-max-clamp/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The CSS math functions, &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, and &lt;code&gt;clamp()&lt;/code&gt; are very powerful, well
supported, and could be just what you&#39;re looking for to help you build
responsive UIs. For more resources, check out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Values_and_units&quot; rel=&quot;noopener&quot;&gt;CSS Values and Units on
MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-values-4/&quot; rel=&quot;noopener&quot;&gt;CSS Values and Units Level 4 Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/using-max-for-an-inner-element-max-width/&quot; rel=&quot;noopener&quot;&gt;CSS Tricks Article on Inner-Element Width&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/css-min-max-clamp/&quot; rel=&quot;noopener&quot;&gt;min(), max(), clamp() Overview by Ahmad Shadeed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cover image from &lt;a href=&quot;https://unsplash.com/@yer_a_wizard&quot; rel=&quot;noopener&quot;&gt;@yer_a_wizard&lt;/a&gt; on
Unsplash.&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>`content-visibility`: the new CSS property that boosts your rendering performance</title>
    <link href="https://web.dev/content-visibility/"/>
    <updated>2020-08-05T00:00:00Z</updated>
    <id>https://web.dev/content-visibility/</id>
    <content type="html" mode="escaped">&lt;p&gt;The
&lt;a href=&quot;https://drafts.csswg.org/css-contain/#propdef-content-visibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;content-visibility&lt;/code&gt;&lt;/a&gt;
property, launching in Chromium 85, might be one of the most impactful new CSS
properties for improving page load performance. &lt;code&gt;content-visibility&lt;/code&gt; enables the
user agent to skip an element&#39;s rendering work, including layout and painting,
until it is needed. Because rendering is skipped, if a large portion of your
content is off-screen, leveraging the &lt;code&gt;content-visibility&lt;/code&gt; property makes the
initial user load much faster. It also allows for faster interactions with the
on-screen content. Pretty neat.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;demo with figures representing network results&quot; decoding=&quot;async&quot; height=&quot;554&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/v6WcSx9Fq76lCD0iqFCQ.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;In our article demo, applying &lt;code&gt;content-visibility: auto&lt;/code&gt; to chunked content areas gives a &lt;b&gt;7x&lt;/b&gt; rendering performance boost on initial load. Read on to learn more.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;support&quot;&gt;Browser support &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#support&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 85, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      85
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox preview, Preview&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;preview&quot; title=&quot;Preview&quot; aria-label=&quot;Preview&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge 85, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
85
&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari, Not supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/content-visibility#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;content-visibility&lt;/code&gt; relies on primitives within the &lt;a href=&quot;http://drafts.csswg.org/css-contain/&quot; rel=&quot;noopener&quot;&gt;the CSS Containment
Spec&lt;/a&gt;. While &lt;code&gt;content-visibility&lt;/code&gt; is only
supported in Chromium 85 for now (and deemed &lt;a href=&quot;https://github.com/mozilla/standards-positions/issues/135&quot; rel=&quot;noopener&quot;&gt;&amp;quot;worth
prototyping&amp;quot;&lt;/a&gt; for
Firefox), the Containment Spec is supported in &lt;a href=&quot;https://caniuse.com/#feat=css-containment&quot; rel=&quot;noopener&quot;&gt;most modern
browsers&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;containment&quot;&gt;CSS Containment &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#containment&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The key and overarching goal of CSS containment is to enable rendering
performance improvements of web content by providing &lt;strong&gt;predictable isolation of
a DOM subtree&lt;/strong&gt; from the rest of the page.&lt;/p&gt;
&lt;p&gt;Basically a developer can tell a browser what parts of the page are encapsulated
as a set of content, allowing the browsers to reason about the content without
needing to consider state outside of the subtree. Knowing which bits of content
(subtrees) contain isolated content means the browser can make optimization
decisions for page rendering.&lt;/p&gt;
&lt;p&gt;There are four types of &lt;a href=&quot;https://web.dev/css-containment/&quot;&gt;CSS
containment&lt;/a&gt;,
each a potential value for the &lt;code&gt;contain&lt;/code&gt; CSS property, which can be combined
in a space-separated list of values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt;: Size containment on an element ensures that the element&#39;s box can be
laid out without needing to examine its descendants. This means we can
potentially skip layout of the descendants if all we need is the size of the
element.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;layout&lt;/code&gt;: Layout containment means that the descendants do not affect the
external layout of other boxes on the page. This allows us to potentially skip
layout of the descendants if all we want to do is lay out other boxes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt;: Style containment ensures that properties which can have effects on
more than just its descendants don&#39;t escape the element (e.g. counters). This
allows us to potentially skip style computation for the descendants if all we
want is to compute styles on other elements.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paint&lt;/code&gt;: Paint containment ensures that the descendants of the containing box
don&#39;t display outside its bounds. Nothing can visibly overflow the element,
and if an element is off-screen or otherwise not visible, its descendants will
also not be visible. This allows us to potentially skip painting the
descendants if the element is offscreen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;skipping-rendering-work-with-content-visibility&quot;&gt;Skipping rendering work with &lt;code&gt;content-visibility&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#skipping-rendering-work-with-content-visibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It may be hard to figure out which containment values to use, since browser
optimizations may only kick in when an appropriate set is specified. You can
play around with the values to see &lt;a href=&quot;https://web.dev/css-containment/&quot;&gt;what works
best&lt;/a&gt;, or you
can use another CSS property called &lt;code&gt;content-visibility&lt;/code&gt; to apply the needed
containment automatically. &lt;code&gt;content-visibility&lt;/code&gt; ensures that you get the largest
performance gains the browser can provide with minimal effort from you as a
developer.&lt;/p&gt;
&lt;p&gt;The content-visibility property accepts several values, but &lt;code&gt;auto&lt;/code&gt; is the one
that provides immediate performance improvements. An element that has
&lt;code&gt;content-visibility: auto&lt;/code&gt; gains &lt;code&gt;layout&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt; and &lt;code&gt;paint&lt;/code&gt; containment. If
the element is off-screen (and not otherwise relevant to the user—relevant
elements would be the ones that have focus or selection in their subtree), it
also gains &lt;code&gt;size&lt;/code&gt; containment (and it stops
&lt;a href=&quot;https://developer.chrome.com/blog/inside-browser-part3/#paint&quot; rel=&quot;noopener&quot;&gt;painting&lt;/a&gt;
and
&lt;a href=&quot;https://developer.chrome.com/blog/inside-browser-part4/#finding-the-event-target&quot; rel=&quot;noopener&quot;&gt;hit-testing&lt;/a&gt;
its contents).&lt;/p&gt;
&lt;p&gt;What does this mean? In short, if the element is off-screen its descendants are
not rendered. The browser determines the size of the element without considering
any of its contents, and it stops there. Most of the rendering, such as styling
and layout of the element&#39;s subtree are skipped.&lt;/p&gt;
&lt;p&gt;As the element approaches the viewport, the browser no longer adds the &lt;code&gt;size&lt;/code&gt;
containment and starts painting and hit-testing the element&#39;s content. This
enables the rendering work to be done just in time to be seen by the user.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The browser is only able to skip rendering work if you are also careful not to call any DOM API that &lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a#file-what-forces-layout-md&quot;&gt;forces some of rendering to occur&lt;/a&gt; on one of the skipped subtrees. If you&#39;re using &lt;code&gt;content-visibility&lt;/code&gt; to improve performance, audit your code to make sure these APIs are not getting called. To help find them, Chromium will print console messages if you call one of these APIs for a subtree of an element with &lt;code&gt;content-visibility:hidden&lt;/code&gt;. To see the messages, &lt;a href=&quot;https://developer.chrome.com/docs/devtools/console/log/&quot;&gt;turn on verbose logging&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;a-note-on-accessibility&quot;&gt;A note on accessibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#a-note-on-accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the features of &lt;code&gt;content-visibility: auto&lt;/code&gt; is that the off-screen content remains available in the document object model and therefore, the accessibility tree (unlike with &lt;code&gt;visibility: hidden&lt;/code&gt;). This means, that content can be searched for on the page, and navigated to, without waiting for it to load or sacrificing rendering performance.&lt;/p&gt;
&lt;p&gt;The flip-side of this, however, is that &lt;a href=&quot;https://www.w3.org/TR/wai-aria-1.1/#landmark_roles&quot; rel=&quot;noopener&quot;&gt;landmark&lt;/a&gt; elements with style features such as &lt;code&gt;display: none&lt;/code&gt; or &lt;code&gt;visibility: hidden&lt;/code&gt; will also appear in the accessibility tree when off-screen, since the browser will not render these styles until they enter the viewport. To prevent these from being visible in the accessibility tree, potentially causing clutter, be sure to also add &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; In Chromium 85-89, off-screen children within &lt;code&gt;content-visibility: auto&lt;/code&gt; were marked as invisible. In particular, &lt;a href=&quot;https://marcysutton.com/content-visibility-accessible-semantics&quot;&gt;headings&lt;/a&gt; and landmark roles were not exposed to accessibility tools. In Chromium 90 this was updated so that they are exposed. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;example&quot;&gt;Example: a travel blog &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#example&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/content-visibility/travel_blog.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;In this example, we baseline our travel blog on the right, and apply &lt;code&gt;content-visibility: auto&lt;/code&gt; to chunked areas on the left. The results show rendering times going from &lt;b&gt;232ms&lt;/b&gt; to &lt;b&gt;30ms&lt;/b&gt; on initial page load.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A travel blog typically contains a set of stories with a few pictures, and some
descriptive text. Here is what happens in a typical browser when it navigates to
a travel blog:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A part of the page is downloaded from the network, along with any needed
resources.&lt;/li&gt;
&lt;li&gt;The browser styles and lays out all of the contents of the page, without
considering if the content is visible to the user.&lt;/li&gt;
&lt;li&gt;The browser goes back to step 1 until all of the page and resources are
downloaded.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In step 2, the browser processes all of the contents looking for things that may
have changed. It updates the style and layout of any new elements, along with
the elements that may have shifted as a result of new updates. This is rendering
work. This takes time.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of a travel blog.&quot; decoding=&quot;async&quot; height=&quot;563&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/57Zh2hjcXJjJIBSE648j.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;An example of a travel blog. See &lt;a href=&quot;https://codepen.io/una/pen/rNxEWLo&quot;&gt;Demo on Codepen&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Now consider what happens if you put &lt;code&gt;content-visibility: auto&lt;/code&gt; on each of the
individual stories in the blog. The general loop is the same: the browser
downloads and renders chunks of the page. However, the difference is in the
amount of work that it does in step 2.&lt;/p&gt;
&lt;p&gt;With content-visibility, it will style and layout all of the contents that are
currently visible to the user (they are on-screen). However, when processing the
story that is fully off-screen, the browser will skip the rendering work and
only style and layout the element box itself.&lt;/p&gt;
&lt;p&gt;The performance of loading this page would be as if it contained full on-screen
stories and empty boxes for each of the off-screen stories. This performs much
better, with &lt;em&gt;expected reduction of 50% or more&lt;/em&gt; from the rendering cost of
loading. In our example, we see a boost from a &lt;strong&gt;232ms&lt;/strong&gt; rendering time to a
&lt;strong&gt;30ms&lt;/strong&gt; rendering time. That&#39;s a &lt;strong&gt;7x&lt;/strong&gt; performance boost.&lt;/p&gt;
&lt;p&gt;What is the work that you need to do in order to reap these benefits? First, we
chunk the content into sections:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;An annotated screenshot of chunking content into sections with a CSS class.&quot; decoding=&quot;async&quot; height=&quot;563&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/29uexe2kBwIsrAuILPnp.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Example of chunking content into sections with the &lt;code&gt;story&lt;/code&gt; class applied, to receive &lt;code&gt;content-visibility: auto&lt;/code&gt;. See &lt;a href=&quot;https://codepen.io/vmpstr/pen/xxZoyMb&quot;&gt;Demo on Codepen&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Then, we apply the following style rule to the sections:&lt;/p&gt;
&lt;div&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;.story&lt;/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-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1000px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Explained in the next section. */&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&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Note that as content moves in and out of visibility, it will start and stop being rendered as needed. However, this does not mean that the browser will have to render and re-render the same content over and over again, since the rendering work is saved when possible. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;specifying-the-natural-size-of-an-element-with-contain-intrinsic-size&quot;&gt;Specifying the natural size of an element with &lt;code&gt;contain-intrinsic-size&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#specifying-the-natural-size-of-an-element-with-contain-intrinsic-size&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to realize the potential benefits of &lt;code&gt;content-visibility&lt;/code&gt;, the browser
needs to apply size containment to ensure that the rendering results of contents
do not affect the size of the element in any way. This means that the element
will lay out as if it was empty. If the element does not have a height specified
in a regular block layout, then it will be of 0 height.&lt;/p&gt;
&lt;p&gt;This might not be ideal, since the size of the scrollbar will shift, being
reliant on each story having a non-zero height.&lt;/p&gt;
&lt;p&gt;Thankfully, CSS provides another property, &lt;code&gt;contain-intrinsic-size&lt;/code&gt;, which
effectively specifies the natural size of the element &lt;em&gt;if the element is
affected by size containment&lt;/em&gt;. In our example, we are setting it to &lt;code&gt;1000px&lt;/code&gt; as
an estimate for the height and width of the sections.&lt;/p&gt;
&lt;p&gt;This means it will lay out as if it had a single child of &amp;quot;intrinsic-size&amp;quot;
dimensions, ensuring that your unsized divs still occupy space.
&lt;code&gt;contain-intrinsic-size&lt;/code&gt; acts as a placeholder size in lieu of rendered content.&lt;/p&gt;
&lt;p&gt;In Chromium 98 and onward, there is a new &lt;a href=&quot;https://drafts.csswg.org/css-sizing-4/#valdef-contain-intrinsic-width-auto-length&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/a&gt;
keyword for &lt;code&gt;contain-intrinsic-size&lt;/code&gt;. When specified, the browser will remember
the last-rendered size, if any, and use that instead of the developer-provided placeholder
size. For example, if you specified &lt;code&gt;contain-intrinsic-size: auto 300px&lt;/code&gt;, the
element will start out with a &lt;code&gt;300px&lt;/code&gt; intrinsic sizing in each dimension, but once
the element&#39;s contents are rendered, it will retain the rendered intrinsic size.
Any subsequent rendering size changes will also be remembered. In practice, this means that if you
scroll an element with &lt;code&gt;content-visibility: auto&lt;/code&gt; applied, and then scroll it back
offscreen, it will automatically retain its ideal width and height, and not revert
to the placeholder sizing. This feature is especially useful for infinite scrollers,
which can now automatically improve sizing estimation over time as the user
explores the page.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; We can use &lt;code&gt;IntersectionObserver&lt;/code&gt; and &lt;code&gt;MutationObserver&lt;/code&gt; to set the correct sizes inline for each element. &lt;a href=&quot;https://twitter.com/slightlylate&quot;&gt;Alex Russell&lt;/a&gt; explains how this works in &lt;a href=&quot;https://infrequently.org/2020/12/content-visibility-scroll-fix/&quot;&gt;&lt;code&gt;content-visibility&lt;/code&gt; without jittery scrollbars&lt;/a&gt;, and &lt;a href=&quot;https://infrequently.org/2020/12/resize-resilient-deferred-rendering/&quot;&gt;Resize-Resilient &lt;code&gt;content-visibility&lt;/code&gt; Fixes&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;hiding-content-with-content-visibility-hidden&quot;&gt;Hiding content with &lt;code&gt;content-visibility: hidden&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#hiding-content-with-content-visibility-hidden&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What if you want to keep the content unrendered regardless of whether or not it
is on-screen, while leveraging the benefits of cached rendering state? Enter:
&lt;code&gt;content-visibility: hidden&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;content-visibility: hidden&lt;/code&gt; property gives you all of the same benefits of
unrendered content and cached rendering state as &lt;code&gt;content-visibility: auto&lt;/code&gt; does
off-screen. However, unlike with &lt;code&gt;auto&lt;/code&gt;, it does not automatically start to
render on-screen.&lt;/p&gt;
&lt;p&gt;This gives you more control, allowing you to hide an element&#39;s contents and
later unhide them quickly.&lt;/p&gt;
&lt;p&gt;Compare it to other common ways of hiding element&#39;s contents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;display: none&lt;/code&gt;: hides the element and destroys its rendering state. This
means unhiding the element is as expensive as rendering a new element with the
same contents.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visibility: hidden&lt;/code&gt;: hides the element and keeps its rendering state. This
doesn&#39;t truly remove the element from the document, as it (and it&#39;s subtree)
still takes up geometric space on the page and can still be clicked on. It
also updates the rendering state any time it is needed even when hidden.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;content-visibility: hidden&lt;/code&gt;, on the other hand, hides the element while
preserving its rendering state, so, if there are any changes that need to
happen, they only happen when the element is shown again (i.e. the
&lt;code&gt;content-visibility: hidden&lt;/code&gt; property is removed).&lt;/p&gt;
&lt;p&gt;Some great use cases for &lt;code&gt;content-visibility: hidden&lt;/code&gt; are when implementing
advanced virtual scrollers, and measuring layout. They&#39;re also great for
single-page applications (SPA&#39;s). Inactive app views can be left in the DOM with
&lt;code&gt;content-visibility: hidden&lt;/code&gt; applied to prevent their display but maintain their
cached state. This makes the view quick to render when it becomes active again.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; In an experiment, Facebook engineers observed an up to 250ms improvement in navigation times when going back to previously cached views. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;effects-on-interaction-to-next-paint-inp&quot;&gt;Effects on Interaction to Next Paint (INP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#effects-on-interaction-to-next-paint-inp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/inp/&quot;&gt;INP&lt;/a&gt; is a metric that evaluates a page&#39;s ability to be reliably responsive to user input. Responsiveness can be affected by any excessive amount of work that occurs on the main thread, including rendering work.&lt;/p&gt;
&lt;p&gt;Whenever you can reduce rendering work on any given page, you&#39;re giving the main thread an opportunity to respond to user inputs more quickly. This includes rendering work, and using the &lt;code&gt;content-visiblity&lt;/code&gt; CSS property where appropriate can reduce rendering work—especially during startup, when most rendering and layout work is done.&lt;/p&gt;
&lt;p&gt;Reducing rendering work has a direct effect on INP. When users attempt to interact with a page that uses the &lt;code&gt;content-visibility&lt;/code&gt; property properly to defer layout and rendering of offscreen elements, you&#39;re giving the main thread a chance to respond to critical user-visible work. This can improve your page&#39;s INP in some situations.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/content-visibility/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;content-visibility&lt;/code&gt; and the CSS Containment Spec mean some exciting performance
boosts are coming right to your CSS file. For more information on these
properties, check out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://drafts.csswg.org/css-contain/&quot; rel=&quot;noopener&quot;&gt;The CSS Containment Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Containment&quot; rel=&quot;noopener&quot;&gt;MDN Docs on CSS
Containment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/w3c/csswg-drafts&quot; rel=&quot;noopener&quot;&gt;CSSWG Drafts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author><author>
      <name>Vladimir Levin</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>@property: giving superpowers to CSS variables</title>
    <link href="https://web.dev/at-property/"/>
    <updated>2020-07-21T00:00:00Z</updated>
    <id>https://web.dev/at-property/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://ishoudinireadyyet.com/&quot; rel=&quot;noopener&quot;&gt;CSS Houdini&lt;/a&gt; is an umbrella term that covers a
set of low-level APIs that expose parts of the CSS rendering engine, and give
developers access to the CSS Object Model. This is a huge
change for the CSS ecosystem, as it enables developers to tell the browser how
to read and parse custom CSS without waiting for browser vendors to provide
built-in support for these features. So exciting!&lt;/p&gt;
&lt;p&gt;One of the most exciting additions to CSS within the Houdini umbrella is the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CSS_Properties_and_Values_API&quot; rel=&quot;noopener&quot;&gt;Properties and Values
API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This API supercharges your CSS custom properties (also commonly referred to as
CSS variables) by giving them semantic meaning (defined by a syntax) and even
fallback values, enabling CSS testing.&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Firefox, Not supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge, Not supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari, Not supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;writing-houdini-custom-properties&quot;&gt;Writing Houdini custom properties &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/at-property/#writing-houdini-custom-properties&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s an example of setting a custom property (think: CSS variable), but now
with a syntax (type), initial value (fallback), and inheritance boolean (does
it inherit the value from it&#39;s parent or not?). The current way to do this is
through &lt;code&gt;CSS.registerProperty()&lt;/code&gt; in JavaScript, but in Chromium 85 and later, the
&lt;code&gt;@property&lt;/code&gt; syntax will be supported in your CSS files:&lt;/p&gt;
&lt;div class=&quot;switcher&quot;&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Separate JavaScript file (Chromium 78)&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&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;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;--colorPrimary&#39;&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;syntax&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;color&gt;&#39;&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;initialValue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;magenta&#39;&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;inherits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&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&gt;&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Included in CSS file (Chromium 85)&lt;/p&gt;
&lt;div&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; --colorPrimary&lt;/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;&#39;&amp;lt;color&gt;&#39;&lt;/span&gt;&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; magenta&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; false&lt;span 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&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Now you can access &lt;code&gt;--colorPrimary&lt;/code&gt; like any other CSS custom property, via
&lt;code&gt;var(--colorPrimary)&lt;/code&gt;. However, the difference here is that &lt;code&gt;--colorPrimary&lt;/code&gt; isn&#39;t
just read as a string. It has data!&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; When writing a registered custom property with a specified &lt;code&gt;syntax&lt;/code&gt;, you &lt;em&gt;must&lt;/em&gt; also include an &lt;code&gt;initial-value&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;fallback-values&quot;&gt;Fallback values &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/at-property/#fallback-values&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As with any other custom property, you can get (using var) or set
(write/rewrite) values, but with Houdini custom properties, if you set a falsey
value when overriding it, the CSS rendering engine will send the initial value
(its fallback value) instead of ignoring the line.&lt;/p&gt;
&lt;p&gt;Consider the example below. The &lt;code&gt;--colorPrimary&lt;/code&gt; variable has an
&lt;code&gt;initial-value&lt;/code&gt; of &lt;code&gt;magenta&lt;/code&gt;. But the developer has given it the invalid
value &amp;quot;23&amp;quot;. Without &lt;code&gt;@property&lt;/code&gt;, the CSS parser would ignore the
invalid code. Now, the parser falls back to &lt;code&gt;magenta&lt;/code&gt;. This allows for
true fallbacks and testing within CSS. Neat!&lt;/p&gt;
&lt;div&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;--colorPrimary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* magenta */&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;.highlight-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;--colorPrimary&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;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;--colorPrimary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* yellow */&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;.another-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;--colorPrimary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 23&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;--colorPrimary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* magenta */&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&gt;&lt;h2 id=&quot;syntax&quot;&gt;Syntax &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/at-property/#syntax&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the syntax feature, you can now write semantic CSS by specifying
a type. The current types that are allowed include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;number&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;percentage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length-percentage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;image&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;integer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;angle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resolution&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transform-list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transform-function&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;custom-ident&lt;/code&gt; (a custom identifier string)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Setting a syntax enables the browser to type-check custom properties.
This has many benefits.&lt;/p&gt;
&lt;p&gt;To illustrate this point, I&#39;ll show you how to animate a gradient. Currently,
there is no way to smoothly animate (or interpolate) between gradient values, as
each gradient declaration is parsed as a string.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://storage.googleapis.com/web-dev-assets/at-property/support1.gif&quot; /&gt;
  &lt;figcaption&gt;
    Using a custom property with a &quot;number&quot; syntax, the gradient on the left shows a smooth
    transition between stop values. The gradient on the right uses a default custom property
    (no syntax defined) and shows an abrupt transition.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;!-- &lt;figure&gt;
  &lt;video controls autoplay loop muted playsinline&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/at-property/support1.mp4&quot; type=&quot;video/mp4&quot;&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Using a custom property with a &quot;number&quot; syntax, the gradient on the left shows a smooth
    transition between stop values. The gradient on the right uses a default custom property
    (no syntax defined) and shows an abrupt transition.
  &lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;p&gt;In this example, the gradient stop percentage is being animated from a starting
value of 40% to an ending value of 100% via a hover interaction. You should see a
smooth transition of that top gradient color downward.&lt;/p&gt;
&lt;p&gt;The browser on the left supports the Houdini Properties and Values API,
enabling a smooth gradient stop transition. The browser on the right does not. The
non-supporting browser is only able to understand this change as a string going
from point A to point B. There is no opportunity to interpolate the values, and
thus you don&#39;t see that smooth transition.&lt;/p&gt;
&lt;p&gt;However, if you declare syntax type when writing custom properties, and then use
those custom properties to enable the animation, you&#39;ll see the transition. You
can instantiate the custom property &lt;code&gt;--gradPoint&lt;/code&gt; like so:&lt;/p&gt;
&lt;div&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;/* Check for Houdini support &amp;amp; register property */&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;background&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;something&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 atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@property&lt;/span&gt; --gradPoint&lt;/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;&#39;&amp;lt;percentage&gt;&#39;&lt;/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; false&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; 40%&lt;span class=&quot;token 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&gt;&lt;p&gt;And then when it comes time to animate it, you can update the value from the initial &lt;code&gt;40%&lt;/code&gt; to &lt;code&gt;100%&lt;/code&gt;:&lt;/p&gt;
&lt;div&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 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; &lt;span class=&quot;token function&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;something&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;.post:hover,&lt;br /&gt;  .post: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;--gradPoint&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This will now enable that smooth gradient transition.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://storage.googleapis.com/web-dev-assets/at-property/demo.gif&quot; /&gt;
  &lt;figcaption&gt;
    Smoothly transitioning gradient borders. &lt;a href=&quot;https://glitch.com/~houdini-gradient-borders&quot;&gt;See Demo on Glitch&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;!--
&lt;figure&gt;
  &lt;video controls autoplay loop muted playsinline&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/at-property/demo.mp4&quot; type=&quot;video/mp4&quot;&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Smoothly transitioning gradient borders. &lt;a href=&quot;https://glitch.com/~houdini-gradient-borders&quot;&gt;See Demo on Glitch&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/at-property/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@property&lt;/code&gt; rule makes an exciting technology even more accessible by
allowing you to write semantically meaningful CSS within CSS itself. To learn
more about CSS Houdini and the Properties and Values API, check out these
resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://ishoudinireadyyet.com/&quot; rel=&quot;noopener&quot;&gt;Is Houdini Ready Yet?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Houdini&quot; rel=&quot;noopener&quot;&gt;MDN Houdini Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/css-props-and-vals/&quot;&gt;Smarter custom properties with Houdini&#39;s new API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/w3c/css-houdini-drafts/issues&quot; rel=&quot;noopener&quot;&gt;Houdini CSSWG Issue Queue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@cristian1&quot; rel=&quot;noopener&quot;&gt;Cristian Escobar&lt;/a&gt; on Unsplash.&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>Ten modern layouts in one line of CSS</title>
    <link href="https://web.dev/one-line-layouts/"/>
    <updated>2020-07-07T00:00:00Z</updated>
    <id>https://web.dev/one-line-layouts/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;qm0IfG1GyZU&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;Modern CSS layouts enable developers to write really meaningful and robust styling rules with just a few keystrokes. The talk above and this subsequent post examine 10 powerful lines of CSS that do some serious heavy lifting.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/1linelayouts?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=README.md&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;1linelayouts on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;To follow along or play with these demos on your own, check out the Glitch embed above, or visit &lt;a href=&quot;https://1linelayouts.glitch.me/&quot; rel=&quot;noopener&quot;&gt;1linelayouts.glitch.me&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;01-super-centered-place-items-center&quot;&gt;01. Super Centered: &lt;code&gt;place-items: center&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#01-super-centered-place-items-center&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/01-place-items-center.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;For the  first &#39;single-line&#39; layout, let&#39;s solve the biggest mystery in all of the CSS land: centering things. I want you to know that it&#39;s easier than you think with &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/place-items&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;place-items: center&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First specify &lt;code&gt;grid&lt;/code&gt; as the &lt;code&gt;display&lt;/code&gt; method, and then write &lt;code&gt;place-items: center&lt;/code&gt; on the same element. &lt;code&gt;place-items&lt;/code&gt; is a shorthand to set both &lt;code&gt;align-items&lt;/code&gt; and &lt;code&gt;justify-items&lt;/code&gt; at once. By setting it to &lt;code&gt;center&lt;/code&gt;, both &lt;code&gt;align-items&lt;/code&gt; and &lt;code&gt;justify-items&lt;/code&gt; are set to  &lt;code&gt;center&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This enables the content to be perfectly centered within the parent, regardless of intrinsic size.&lt;/p&gt;
&lt;h2 id=&quot;02-the-deconstructed-pancake-flex-lessgrowgreater-lessshrinkgreater-lessbasewidthgreater&quot;&gt;02. The Deconstructed Pancake: &lt;code&gt;flex: &amp;lt;grow&amp;gt; &amp;lt;shrink&amp;gt; &amp;lt;baseWidth&amp;gt;&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#02-the-deconstructed-pancake-flex-lessgrowgreater-lessshrinkgreater-lessbasewidthgreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/02-deconstructed-pancake-1.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Next we have the deconstructed pancake! This is a common layout for marketing sites, for example, which may have a row of 3 items, usually with an image, title, and then some text, describing some features of a product. On mobile, we&#39;ll want those to stack nicely, and expand as we increase the screen size.&lt;/p&gt;
&lt;p&gt;By using Flexbox for this effect, you won&#39;t need media queries to adjust the placement of these elements when the screen resizes.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/flex&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;flex&lt;/code&gt;&lt;/a&gt; shorthand stands for: &lt;code&gt;flex: &amp;lt;flex-grow&amp;gt; &amp;lt;flex-shrink&amp;gt; &amp;lt;flex-basis&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because of this, if you want your boxes to fill out to their &lt;code&gt;&amp;lt;flex-basis&amp;gt;&lt;/code&gt; size, shrink on smaller sizes, but not &lt;em&gt;stretch&lt;/em&gt; to fill any additional space, write: &lt;code&gt;flex: 0 1 &amp;lt;flex-basis&amp;gt;&lt;/code&gt;. In this case, your &lt;code&gt;&amp;lt;flex-basis&amp;gt;&lt;/code&gt; is &lt;code&gt;150px&lt;/code&gt; so it looks like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 1 150px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you &lt;em&gt;do&lt;/em&gt; want the boxes to stretch and fill the space as they wrap to the next line, set the &lt;code&gt;&amp;lt;flex-grow&amp;gt;&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;, so it would look like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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 150px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/02-deconstructed-pancake-2.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Now, as you increase or decrease the screen size,  these flex items both shrink and grow.&lt;/p&gt;
&lt;h2 id=&quot;03-sidebar-says-grid-template-columns-minmaxlessmingreater,-lessmaxgreater&quot;&gt;03. Sidebar Says: &lt;code&gt;grid-template-columns: minmax(&amp;lt;min&amp;gt;, &amp;lt;max&amp;gt;) …)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#03-sidebar-says-grid-template-columns-minmaxlessmingreater,-lessmaxgreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/03-sidebar-says.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;This demo takes advantage of the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/minmax&quot; rel=&quot;noopener&quot;&gt;minmax&lt;/a&gt; function for grid layouts. What we&#39;re doing here is setting the minimum sidebar size to be &lt;code&gt;150px&lt;/code&gt;, but on larger screens, letting that stretch out to &lt;code&gt;25%&lt;/code&gt;. The sidebar will always take up &lt;code&gt;25%&lt;/code&gt; of its parent&#39;s horizontal space until that &lt;code&gt;25%&lt;/code&gt; becomes smaller than &lt;code&gt;150px&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add this as a value of grid-template-columns with the following value:
&lt;code&gt;minmax(150px, 25%) 1fr&lt;/code&gt;. The item in the first column (the sidebar in this case) gets a &lt;code&gt;minmax&lt;/code&gt; of &lt;code&gt;150px&lt;/code&gt; at &lt;code&gt;25%&lt;/code&gt;, and the second item (the &lt;code&gt;main&lt;/code&gt; section here) takes up the rest of the space as a single &lt;code&gt;1fr&lt;/code&gt; track.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;minmax&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;150px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 1fr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;04-pancake-stack-grid-template-rows-auto-1fr-auto&quot;&gt;04. Pancake Stack: &lt;code&gt;grid-template-rows: auto 1fr auto&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#04-pancake-stack-grid-template-rows-auto-1fr-auto&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/04-pancake-stack.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Unlike the Deconstructed Pancake, this example does not wrap its children when the screen size changes. Commonly referred to as a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/Layout_cookbook/Sticky_footers&quot; rel=&quot;noopener&quot;&gt;sticky footer&lt;/a&gt;, this layout is often used for both websites and apps, across mobile applications (the footer is commonly a toolbar), and websites (single page applications often use this global layout).&lt;/p&gt;
&lt;p&gt;Adding &lt;code&gt;display: grid&lt;/code&gt; to the component will give you a single column grid, however the main area will only be as tall as the content with the footer below it.&lt;/p&gt;
&lt;p&gt;To make the footer stick to the bottom,  add:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template-rows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto 1fr auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This sets the header and footer content to automatically take the size of its children, and applies the remaining space (&lt;code&gt;1fr&lt;/code&gt;) to the main area, while the &lt;code&gt;auto&lt;/code&gt; sized row will take the size of the minimum content of its children, so as that content increases in size, the row itself will grow to adjust.&lt;/p&gt;
&lt;h2 id=&quot;05-classic-holy-grail-layout-grid-template-auto-1fr-auto-auto-1fr-auto&quot;&gt;05. Classic Holy Grail Layout: &lt;code&gt;grid-template: auto 1fr auto / auto 1fr auto&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#05-classic-holy-grail-layout-grid-template-auto-1fr-auto-auto-1fr-auto&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/05-holy-grail.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;For this classic holy grail layout, there is a header, footer, left sidebar, right sidebar, and main content. It&#39;s similar to the previous layout, but now with sidebars!&lt;/p&gt;
&lt;p&gt;To write this entire grid using a single line of code, use the &lt;code&gt;grid-template&lt;/code&gt; property. This enables you to set both the rows and columns at the same time.&lt;/p&gt;
&lt;p&gt;The property and value pair is: &lt;code&gt;grid-template: auto 1fr auto / auto 1fr auto&lt;/code&gt;. The slash in between the first and second space-separated lists is the break between rows and columns.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;grid-template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto 1fr auto / auto 1fr auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As in the last example, where the header and footer had auto-sized content, here the left and right sidebar are automatically sized based on their children&#39;s intrinsic size. However, this time it is horizontal size (width) instead of vertical (height).&lt;/p&gt;
&lt;h2 id=&quot;06-12-span-grid-grid-template-columns-repeat12,-1fr&quot;&gt;06. 12-Span Grid: &lt;code&gt;grid-template-columns: repeat(12, 1fr)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#06-12-span-grid-grid-template-columns-repeat12,-1fr&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/06-12-span-1.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Next we have another classic: the 12-span grid. You can quickly write grids in CSS with the &lt;code&gt;repeat()&lt;/code&gt; function. Using: &lt;code&gt;repeat(12, 1fr);&lt;/code&gt; for the grid template columns gives you 12 columns each of &lt;code&gt;1fr&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;12&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.child-span-12&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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 / 13&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now you have a 12 column track grid, we can place our children on the grid. One way to do this would be to place them using grid lines. For example, &lt;code&gt;grid-column: 1 / 13&lt;/code&gt; would span all the way from the first line to the last (13th) and span 12 columns. &lt;code&gt;grid-column: 1 / 5;&lt;/code&gt; would span the first four.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/06-12-span-2.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Another way to write this is by using the &lt;code&gt;span&lt;/code&gt; keyword. With &lt;code&gt;span&lt;/code&gt;, you set the starting line and then how many columns to span into from that starting point. In this case, &lt;code&gt;grid-column: 1 / span 12&lt;/code&gt; would be equivalent to &lt;code&gt;grid-column: 1 / 13&lt;/code&gt;, and &lt;code&gt;grid-column: 2 / span 6&lt;/code&gt; would be equivalent to &lt;code&gt;grid-column: 2 / 8&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.child-span-12&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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 / span 12&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;07-ram-repeat,-auto,-minmax-grid-template-columnsauto-fit,-minmaxlessbasegreater,-1fr&quot;&gt;07. RAM (Repeat, Auto, MinMax): &lt;code&gt;grid-template-columns(auto-fit, minmax(&amp;lt;base&amp;gt;, 1fr))&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#07-ram-repeat,-auto,-minmax-grid-template-columnsauto-fit,-minmaxlessbasegreater,-1fr&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/07-ram-1.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;For this seventh example, combine some of the concepts you&#39;ve already learned about to create a responsive layout with automatically-placed and flexible children. Pretty neat. The key terms to remember here are &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;auto-(fit|fill)&lt;/code&gt;, and &lt;code&gt;minmax()&#39;&lt;/code&gt;, which you remember by the acronym RAM.&lt;/p&gt;
&lt;p&gt;All together, it looks like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;150px&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You are using repeat again, but this time, using the &lt;code&gt;auto-fit&lt;/code&gt; keyword instead of an explicit numeric value. This enables auto-placement of these child elements. These children also have a base minimum value of &lt;code&gt;150px&lt;/code&gt; with a maximum value &lt;code&gt;1fr&lt;/code&gt;, meaning on smaller screens, they will take up the full &lt;code&gt;1fr&lt;/code&gt; width, and as they reach &lt;code&gt;150px&lt;/code&gt; wide each, they will start to flow onto the same line.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;auto-fit&lt;/code&gt;, the boxes will stretch as their horizontal size exceeds 150px to fill the entire remaining space. However, if you change this to &lt;code&gt;auto-fill&lt;/code&gt;, they will not stretch when their base size in the minmax function is exceeded:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/07-ram-2.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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-fill&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;150px&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;08-line-up-justify-content-space-between&quot;&gt;08. Line Up: &lt;code&gt;justify-content: space-between&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#08-line-up-justify-content-space-between&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/08-lineup.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;For the next layout, the main point to demonstrate here is &lt;code&gt;justify-content: space-between&lt;/code&gt;, which places the first and last child elements at the edges of their bounding box, with the remaining space evenly distributed between the elements. For these cards, they are placed in a Flexbox display mode, with the direction being set to column using &lt;code&gt;flex-direction: column&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This places the title, description, and image block in a vertical column inside of the parent card. Then, applying &lt;code&gt;justify-content: space-between&lt;/code&gt; anchors the first (title) and last (image block) elements to the edges of the flexbox, and the descriptive text in between those gets placed with equal spacing to each endpoint.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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; space-between&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;09-clamping-my-style-clamplessmingreater,-lessactualgreater,-lessmaxgreater&quot;&gt;09. Clamping My Style: &lt;code&gt;clamp(&amp;lt;min&amp;gt;, &amp;lt;actual&amp;gt;, &amp;lt;max&amp;gt;)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#09-clamping-my-style-clamplessmingreater,-lessactualgreater,-lessmaxgreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/09-clamping.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;Here&#39;s where we get into some techniques with &lt;a href=&quot;https://caniuse.com/#feat=css-math-functions&quot; rel=&quot;noopener&quot;&gt;less browser support&lt;/a&gt;, but have some really exciting implications for layouts and responsive UI design. In this demo, you are setting the width using clamp like so: &lt;code&gt;width: clamp(&amp;lt;min&amp;gt;, &amp;lt;actual&amp;gt;, &amp;lt;max&amp;gt;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This sets an absolute min and max size, and an actual size. With values, that can look like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.parent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;23ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 60%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 46ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The minimum size here is &lt;code&gt;23ch&lt;/code&gt; or 23 character units, and the maximum size is &lt;code&gt;46ch&lt;/code&gt;, 46 characters. &lt;a href=&quot;https://meyerweb.com/eric/thoughts/2018/06/28/what-is-the-css-ch-unit/&quot; rel=&quot;noopener&quot;&gt;Character width units&lt;/a&gt; are based on the font size of the element (specifically the width of the &lt;code&gt;0&lt;/code&gt; glyph). The &#39;actual&#39; size is 50%, which represents 50% of this element&#39;s parent width.&lt;/p&gt;
&lt;p&gt;What the &lt;code&gt;clamp()&lt;/code&gt; function is doing here is enabling this element to retain a 50% width &lt;em&gt;until&lt;/em&gt; 50% is either greater than &lt;code&gt;46ch&lt;/code&gt; (on wider viewports), or smaller than &lt;code&gt;23ch&lt;/code&gt; (on smaller viewports). You can see that as I stretch and shrink the parent size, the width of this card increases to its clamped maximum point and decreases to its clamped minimum. It then stays centered in the parent since we&#39;ve applied additional properties to center it. This enables more legible layouts, as the text won&#39;t be too wide (above &lt;code&gt;46ch&lt;/code&gt;) or too squished and narrow (less than &lt;code&gt;23ch&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This is also a great way to implement responsive typography. For example, you could write: &lt;code&gt;font-size: clamp(1.5rem, 20vw, 3rem)&lt;/code&gt;. In this case, the font-size of a headline would always stay clamped between &lt;code&gt;1.5rem&lt;/code&gt; and &lt;code&gt;3rem&lt;/code&gt; but would grow and shrink based on the &lt;code&gt;20vw&lt;/code&gt; actual value to fit the width of of the viewport.&lt;/p&gt;
&lt;p&gt;This is a great technique to ensure legibility with a minimum and maximum size value, but remember it is not supported in all modern browsers so make sure you have fallbacks and do your testing.&lt;/p&gt;
&lt;h2 id=&quot;10-respect-for-aspect-aspect-ratio-lesswidthgreater-lessheightgreater&quot;&gt;10. Respect for Aspect: &lt;code&gt;aspect-ratio: &amp;lt;width&amp;gt; / &amp;lt;height&amp;gt;&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#10-respect-for-aspect-aspect-ratio-lesswidthgreater-lessheightgreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/one-line-layouts/10-aspectratio.mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;And finally, this last layout tool is the most experimental of the bunch. It was recently introduced to Chrome Canary in Chromium 84, and there is active effort from Firefox in getting this implemented, but it is not currently in any stable browser editions.&lt;/p&gt;
&lt;p&gt;I do want to mention this, though, because it is such a frequently met problem. And that is just simply maintaining the aspect ratio of an image.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;aspect-ratio&lt;/code&gt; property, as I resize the card, the green visual block maintains this 16 x 9 aspect ratio. We are Respecting the Aspect Ratio with &lt;code&gt;aspect-ratio: 16 / 9&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.video&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To maintain a 16 x 9 aspect ratio without this property, you&#39;d need to use a &lt;a href=&quot;https://css-tricks.com/aspect-ratio-boxes/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;padding-top&lt;/code&gt; hack&lt;/a&gt; and give it a padding of &lt;code&gt;56.25%&lt;/code&gt; to set a top-to-width ratio. We will soon have a property for this to avoid the hack and the need to calculate the percentage. You can make a square with &lt;code&gt;1 / 1&lt;/code&gt; ratio, a 2 to 1 ratio with &lt;code&gt;2 / 1&lt;/code&gt;, and really just anything you need for this image to scale with a set size ratio.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.square&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;While this feature is still up and coming, it it a good one to know about as it resolves a lot of developer strife that I have faced many times myself, especially when it comes to video and iframes.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/one-line-layouts/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thank you for following this journey through 10 powerful lines of CSS. To learn more, watch &lt;a href=&quot;https://youtu.be/qm0IfG1GyZU&quot; rel=&quot;noopener&quot;&gt;the full video&lt;/a&gt;, and try out &lt;a href=&quot;https://1linelayouts.glitch.me/&quot; rel=&quot;noopener&quot;&gt;the demos&lt;/a&gt; yourself.&lt;/p&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author>
  </entry>
  
  <entry>
    <title>Web Animations API improvements in Chromium 84</title>
    <link href="https://web.dev/web-animations/"/>
    <updated>2020-05-27T00:00:00Z</updated>
    <id>https://web.dev/web-animations/</id>
    <content type="html" mode="escaped">&lt;p&gt;When used correctly, &lt;a href=&quot;https://www.researchgate.net/publication/229351931_The_Effects_of_Animation_and_Format_on_the_Perception_and_Memory_of_Online_Advertising&quot; rel=&quot;noopener&quot;&gt;animations improve user perception and memory&lt;/a&gt; of your brand, guide user actions, and help users navigate your application—providing context in a digital space.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/TR/web-animations-1/&quot; rel=&quot;noopener&quot;&gt;Web Animations API&lt;/a&gt; is a tool that enables developers to write &lt;a href=&quot;https://www.youtube.com/watch?v=WaNoqBAp8NI&quot; rel=&quot;noopener&quot;&gt;imperative animations with JavaScript&lt;/a&gt;. It was written to underpin both CSS animation and transition implementations and enable future effects to be developed, as well as existing effects to be composed and timed.&lt;/p&gt;
&lt;p&gt;While &lt;a href=&quot;https://mozilla.github.io/standards-positions/&quot; rel=&quot;noopener&quot;&gt;Firefox&lt;/a&gt; and &lt;a href=&quot;https://webkit.org/status/#specification-web-animations&quot; rel=&quot;noopener&quot;&gt;Safari&lt;/a&gt; have already implemented the full set of spec &lt;a href=&quot;https://caniuse.com/#feat=web-animation&quot; rel=&quot;noopener&quot;&gt;features&lt;/a&gt;, Chromium 84 brings a slew of previously unsupported features to &lt;a href=&quot;https://developer.microsoft.com/en-us/microsoft-edge/status/webanimationsjavascriptapi/&quot; rel=&quot;noopener&quot;&gt;Chrome and Edge&lt;/a&gt; enabling cross-browser interoperability.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The Web Animations API first hit Chromium in version 36, July of 2014. Now the spec is going to be complete, in version 84, launching July 2020.&quot; decoding=&quot;async&quot; height=&quot;374&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mdsjLgrX6rngEnBZo5Nu.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    The long history of the Web Animations API in Chromium.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#getting-started&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Creating an animation via the Web Animations API should feel very familiar if you&#39;ve used &lt;code&gt;@keyframe&lt;/code&gt; rules. First you&#39;ll need to create a Keyframe Object. What might look like &lt;a href=&quot;https://codepen.io/una/pen/RwWMvPw&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; in CSS:&lt;/p&gt;
&lt;div&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; openAnimation&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;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;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;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;/div&gt;&lt;p&gt;would look like &lt;a href=&quot;https://codepen.io/una/pen/abvYXJX&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; in JavaScript:&lt;/p&gt;
&lt;div&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; openAnimation &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 punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;scale(0)&#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 literal-property property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;scale(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;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&gt;&lt;p&gt;Where you set parameters for animation in CSS:&lt;/p&gt;
&lt;div&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;.modal&lt;/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; openAnimation 1s 1 ease-in&lt;span 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&gt;&lt;p&gt;you would set in JS:&lt;/p&gt;
&lt;div&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;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.modal&#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;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    openAnimation&lt;span class=&quot;token punctuation&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;duration&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;span class=&quot;token comment&quot;&gt;// 1s&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;iterations&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;span class=&quot;token comment&quot;&gt;// single iteration&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;easing&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ease-in&#39;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// easing function&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&gt;&lt;p&gt;The amount of code is about the same, but with JavaScript, you get a couple of superpowers that you don&#39;t have with CSS alone. This includes the ability to sequence effects, and an increased control of their play states.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Hyphenated property names become camel case when used in keyframes (e.g. &lt;code&gt;background-color&lt;/code&gt; to &lt;code&gt;backgroundColor&lt;/code&gt;) &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;beyond-elementanimate&quot;&gt;Beyond &lt;code&gt;element.animate()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#beyond-elementanimate&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;However, with the update, the Web Animations API is no longer restricted to animations created via &lt;code&gt;element.animate()&lt;/code&gt;. We can manipulate CSS animations and transitions as well.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;getAnimations()&lt;/code&gt; is a method that returns all animations on an element regardless of whether it was created via &lt;code&gt;element.animate()&lt;/code&gt; or via CSS rules (CSS animation or transition). Here is an example of what this looks like:&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/waapi-getanimations?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=index.html&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;waapi-getanimations on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;You first &lt;code&gt;&amp;quot;get&amp;quot;&lt;/code&gt; the keyframes for the transition to determine where we are transitioning from. Then, you create two new opacity animations, enabling the   cross fade effect. Once the cross-fade completes, you delete the copy.&lt;/p&gt;
&lt;h2 id=&quot;orchestrating-animations-with-promises&quot;&gt;Orchestrating animations with promises &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#orchestrating-animations-with-promises&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Chromium 84, you now have two methods that can be used with promises: &lt;code&gt;animation.ready&lt;/code&gt; and &lt;code&gt;animation.finished&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;animation.ready&lt;/code&gt; enables you to wait for pending changes to take effect (i.e. switching between playback control methods such as play and pause).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;animation.finished&lt;/code&gt; provides a means of executing custom JavaScript code when an animation is complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&#39;s continue with our example, and create an orchestrated animation chain with &lt;code&gt;animation.finished&lt;/code&gt;. Here, you have a vertical transformation (&lt;code&gt;scaleY&lt;/code&gt;), followed by a horizontal transformation (&lt;code&gt;scaleX&lt;/code&gt;), followed by an opacity change on a child element:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/modal-open.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Applying transformations and opacity to an opening modal element. &lt;a href=&quot;https://codepen.io/una/pen/dyYKJMz&quot;&gt;See Demo on Codepen&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transformAnimation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; modal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;openModal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; openModalSettings&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;mark class=&quot;highlight-line highlight-line-active&quot;&gt;transformAnimation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;finished&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;&lt;span class=&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; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fadeIn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fadeInSettings&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We&#39;ve chained these animations using &lt;code&gt;animation.finished.then()&lt;/code&gt; prior to executing the next animation set in the chain. This way, the animations appear in order, and you are even applying effects to different target elements with different options set (such as speed and ease).&lt;/p&gt;
&lt;p&gt;Within CSS, this would be cumbersome to recreate, especially when applying unique, yet sequenced animations to multiple elements. You&#39;d have to use a &lt;code&gt;@keyframe&lt;/code&gt;, sort out the correct timing percentages to place the animations, and use &lt;code&gt;animation-delay&lt;/code&gt; prior to triggering the animations in the sequence.&lt;/p&gt;
&lt;h3 id=&quot;example-play,-pause,-and-reverse&quot;&gt;Example: Play, pause, and reverse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#example-play,-pause,-and-reverse&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What can open, should close! Luckily, since &lt;a href=&quot;https://developer.chrome.com/blog/web-animation-playback/&quot; rel=&quot;noopener&quot;&gt;Chromium 39&lt;/a&gt;, the Web Animations API has provided us the ability to play, pause, and reverse our animations.&lt;/p&gt;
&lt;p&gt;You can take the above animation, and give it a smooth, reversed animation when clicking the button again using &lt;code&gt;.reverse()&lt;/code&gt;. This way, you can create a smoother and more contextual interaction for our modal.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/modal-reverse.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    An example of a modal opening and closing upon button click. &lt;a href=&quot;https://glitch.com/~waapi-promises&quot;&gt;See Demo on Glitch &lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/waapi-promises?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=script.js&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;waapi-promises on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;What you can do is create two play-pending animations (&lt;code&gt;openModal&lt;/code&gt;, and an inline opacity transformation), and then pause one of the animations, delaying it until the other is finished. You can then use promises to wait for each to be finished before playing. Finally, you can check to see if a flag is set, and then reverse each animation.&lt;/p&gt;
&lt;h3 id=&quot;example-dynamic-interactions-with-partial-keyframes&quot;&gt;Example: Dynamic interactions with partial keyframes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#example-dynamic-interactions-with-partial-keyframes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/retargetting.mp4&quot; /&gt;
  &lt;/video&gt;  &lt;figcaption&gt;
    Retargeting example, where a mouse click adjusts the animation to a new location. &lt;a href=&quot;https://glitch.com/~waapi-retargetting&quot;&gt;See Demo on Glitch &lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&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;transform&lt;/span&gt;&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;translate(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;x&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 interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;y&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;span 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 literal-property property&quot;&gt;duration&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;span class=&quot;token literal-property property&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;forwards&#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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this example, there is only one keyframe, and no specified start position. This is an example of using &lt;strong&gt;partial keyframes&lt;/strong&gt;. The mouse handler does a few things here: it sets a new end location and triggers a new animation. The new start position is inferred from the current underlying position.&lt;/p&gt;
&lt;p&gt;New transitions can be triggered while existing ones are still running. This means that the current transition is interrupted, and a new one is created.&lt;/p&gt;
&lt;h2 id=&quot;performance-improvements-with-replaceable-animations&quot;&gt;Performance improvements with replaceable animations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#performance-improvements-with-replaceable-animations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When creating animations based on events, such as on &lt;code&gt;&#39;mousemove&#39;&lt;/code&gt;, a new animation is created each time, which can quickly consume memory and degrade performance.  To address this problem, replaceable animations were introduced in Chromium 83, enabling automated cleanup, where finished animations are flagged as replaceable and automatically removed if replaced by another finished animation. Consider the following example:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/comet-trail.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
  A comet trail animates when the mouse moves. &lt;a href=&quot;https://glitch.com/~waapi-replaced&quot;&gt;See Demo on Glitch&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;elem&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;mousemove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;evt&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; rectangle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span 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 literal-property property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token operator&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;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clientX&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clientY&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&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 literal-property property&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;token operator&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 literal-property property&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;forwards&#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;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&gt;&lt;p&gt;Each time the mouse moves, the browser re-calculates the position for each ball in the comet trail and creates an animation to this new point. The browser now knows to remove old animations (enabling replacement) when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The animation is finished.&lt;/li&gt;
&lt;li&gt;There is one or more animations higher in composite ordering that are also finished.&lt;/li&gt;
&lt;li&gt;The new animations are animating the same properties.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can see exactly how many animations are being replaced by tallying up a counter with each removed animation, using &lt;code&gt;anim.onremove&lt;/code&gt; to trigger the counter.&lt;/p&gt;
&lt;p&gt;There are a few additional methods to take your animation control even further:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;animation.replaceState()&lt;/code&gt; provides a means of tracking whether an animation is active, persisted, or removed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;animation.commitStyles()&lt;/code&gt; updates the style of an element based on the underlying style along with all animations on the element in the composite order.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;animation.persist()&lt;/code&gt; marks an animation as non-replaceable.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;animation.commitStyles()&lt;/code&gt; and &lt;code&gt;animation.persist()&lt;/code&gt; are commonly used with compositing modes, such as &amp;quot;add&amp;quot;. Check out the composite modes demo below to see them in action. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;smoother-animations-with-composite-modes&quot;&gt;Smoother animations with composite modes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#smoother-animations-with-composite-modes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the Web Animations API, you can now set the composite mode of your animations, meaning they can be additive or accumulative, in addition to the default mode of &amp;quot;replace&amp;quot;. &lt;a href=&quot;https://css-tricks.com/additive-animation-web-animations-api/&quot; rel=&quot;noopener&quot;&gt;Composite modes&lt;/a&gt; allow developers to write distinct animations and have control over how effects are combined. Three composite modes are now supported: &lt;code&gt;&#39;replace&#39;&lt;/code&gt; (the default mode), &lt;code&gt;&#39;add&#39;&lt;/code&gt;, and &lt;code&gt;&#39;accumulate&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When you composite animations, a developer can write short, distinct effects and see them combined together. In the example below, we are applying a rotation and scale keyframe to each box, with the only adjustment being the composite mode, added as an option:&lt;/p&gt;
&lt;figure&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/replace-add-accumulate.mp4&quot; /&gt;
  &lt;/video&gt;  &lt;figcaption&gt;
    A demo showing the default, add, and accumulate composite modes. &lt;a href=&quot;https://glitch.com/~waapi-composite-demos&quot;&gt;See Demo on Glitch&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the default &lt;code&gt;&#39;replace&#39;&lt;/code&gt; composite mode, the final animation replaces the transform property and ends up at &lt;code&gt;rotate(360deg) scale(1.4)&lt;/code&gt;. For &lt;code&gt;&#39;add&#39;&lt;/code&gt;, composite adds the rotation and multiplies the scale, resulting in a final state of &lt;code&gt;rotate(720deg) scale(1.96)&lt;/code&gt;. &lt;code&gt;&#39;accumulate&#39;&lt;/code&gt; combines the transformations, resulting in &lt;code&gt;rotate(720deg) scale(1.8)&lt;/code&gt;. For more on the intricacies of these composite modes, check out &lt;a href=&quot;https://www.w3.org/TR/web-animations-1/#the-compositeoperation-enumeration&quot; rel=&quot;noopener&quot;&gt;The CompositeOperation and CompositeOperationOrAuto enumerations&lt;/a&gt; from the Web Animations spec.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at a UI element example:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/web-animations/dropdown.mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
  A bouncy dropdown menu which has two composited animations applied to it. &lt;a href=&quot;https://glitch.com/~waapi-composited&quot;&gt;See Demo on Glitch&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here, two &lt;code&gt;top&lt;/code&gt; animations are composited. The first is a macro-animation, which moves the dropdown by the full height of the menu itself as a slide-in effect from the top of the page, and the second, a micro-animation, applies a little bounce as it hits the bottom. Using the &lt;code&gt;&#39;add&#39;&lt;/code&gt; composite mode enables a smoother transition.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dropDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; menu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;top&lt;/span&gt;&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;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;menuHeight&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 literal-property property&quot;&gt;easing&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ease-in&#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;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;top&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&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;duration&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;forwards&#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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  dropDown&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;finished&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;&lt;span class=&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bounce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; menu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0px&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;easing&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ease-in&#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;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;10px&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;easing&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ease-out&#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;br /&gt;&lt;span class=&quot;highlight-line&quot;&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&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;duration&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;composite&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;add&#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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;whats-next-for-the-web-animations-api&quot;&gt;What&#39;s next for the Web Animations API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-animations/#whats-next-for-the-web-animations-api&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are all exciting additions to animations capabilities in today&#39;s browsers, and even more additions are coming down the pipeline. Check out these future specifications for some further reading on what&#39;s coming next:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-animation-worklet-1/#scroll-timeline&quot; rel=&quot;noopener&quot;&gt;Scroll-linked animations with the Houdini API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#setting-the-timeline&quot; rel=&quot;noopener&quot;&gt;Mutable timelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#grouping-and-synchronization&quot; rel=&quot;noopener&quot;&gt;Group Effect and Synchronization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Una Kravets</name>
    </author><author>
      <name>Kevin Ellis</name>
    </author>
  </entry>
  
  <entry>
    <title>Next-generation web styling</title>
    <link href="https://web.dev/next-gen-css-2019/"/>
    <updated>2019-12-05T00:00:00Z</updated>
    <id>https://web.dev/next-gen-css-2019/</id>
    <content type="html" mode="escaped">&lt;p&gt;There are a &lt;em&gt;ton&lt;/em&gt; of exciting things happening in CSS right now—and
many of them are already supported in today&#39;s browsers!
Our talk at CDS 2019, which you can watch below,
covers several new and upcoming features we thought should get some attention.&lt;/p&gt;
&lt;p&gt;This post focuses on the features you can use today,
so be sure to watch the talk
for a deeper discussion of upcoming features like Houdini.
You can also find demos for all the features we discuss on our
&lt;a href=&quot;https://a.nerdy.dev/css-at-cds&quot; rel=&quot;noopener&quot;&gt;CSS@CDS page&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;-oyeaIirVC0&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;contents&quot;&gt;Contents &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#contents&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#scroll-snap&quot;&gt;Scroll Snap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#focus-within&quot;&gt;&lt;code&gt;:focus-within&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#media-queries-level-5&quot;&gt;Media Queries Level 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#logical-properties&quot;&gt;Logical properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#position-sticky&quot;&gt;&lt;code&gt;position: sticky&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#backdrop-filter&quot;&gt;&lt;code&gt;backdrop-filter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#is&quot;&gt;&lt;code&gt;:is()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#gap&quot;&gt;&lt;code&gt;gap&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#css-houdini&quot;&gt;CSS Houdini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/next-gen-css-2019/#overflow&quot;&gt;Overflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;scroll-snap&quot;&gt;Scroll Snap &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#scroll-snap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Scroll_Snap/Basic_concepts&quot; rel=&quot;noopener&quot;&gt;Scroll Snap&lt;/a&gt; lets you define snap points as the user scrolls your content vertically, horizontally, or  both. It offers built-in scroll inertia and deceleration, and it&#39;s touch enabled.&lt;/p&gt;
&lt;p&gt;This sample code sets up horizontal scrolling in a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; element with snap points aligned to the left sides of child &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; elements:&lt;/p&gt;
&lt;div&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;section&lt;/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-x&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-x&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 property&quot;&gt;scroll-snap-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; x mandatory&lt;span class=&quot;token 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;section &gt; 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;scroll-snap-align&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here&#39;s how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On the parent &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; element,
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;overflow-x&lt;/code&gt; is set to &lt;code&gt;auto&lt;/code&gt; to allow horizontal scrolling.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overscroll-behavior-x&lt;/code&gt; is set to &lt;code&gt;contain&lt;/code&gt; to prevent any parent elements from scrolling when the user reaches the boundaries of the &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; element&#39;s scroll area. (This isn&#39;t strictly necessary for snapping, but it&#39;s usually a good idea.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scroll-snap-type&lt;/code&gt; is set to &lt;code&gt;x&lt;/code&gt;—for horizontal snapping—and &lt;code&gt;mandatory&lt;/code&gt;—to ensure that the viewport always snaps to the closest snap point.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On the child &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; elements, &lt;code&gt;scroll-snap-align&lt;/code&gt; is set to start, which sets the snap points on the left side of each picture (assuming &lt;code&gt;direction&lt;/code&gt; is set to &lt;code&gt;ltr&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here&#39;s a live demo:&lt;/p&gt;
&lt;iframe height=&quot;520&quot; style=&quot;display: block; width: 400px; max-width: 100%; margin: 0 auto;&quot; scrolling=&quot;no&quot; title=&quot;Awww Scroll Snap [horizontal]&quot; src=&quot;https://codepen.io/argyleink/embed/zYYZPqb?height=916&amp;theme-id=dark&amp;default-tab=result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/argyleink/pen/zYYZPqb&quot;&gt;Awww Scroll Snap [horizontal]&lt;/a&gt; by Adam Argyle
  (&lt;a href=&quot;https://codepen.io/argyleink&quot;&gt;@argyleink&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;You can also take a look at demos for &lt;a href=&quot;https://codepen.io/argyleink/pen/oNNZoZj&quot; rel=&quot;noopener&quot;&gt;vertical scroll snap&lt;/a&gt; and &lt;a href=&quot;https://codepen.io/argyleink/pen/MWWpOmz&quot; rel=&quot;noopener&quot;&gt;matrix scroll snap&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; While scroll snap supports vertical snapping, be cautious when using it at the page level since it can feel like control is being taken from the user in some cases. It&#39;s usually best to apply snapping to a component on your page rather than the page itself. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;focus-within&quot;&gt;&lt;code&gt;:focus-within&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#focus-within&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/:focus-within&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;:focus-within&lt;/code&gt;&lt;/a&gt; addresses a long-standing accessibility issue: there are many cases when focusing a child element should affect the presentation of a parent element so that the UI is accessible to users of assistive technologies.&lt;/p&gt;
&lt;p&gt;For example, if you have a dropdown menu with several items, the menu should remain visible while any of the items has focus. Otherwise, the menu disappears for keyboard users.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:focus-within&lt;/code&gt; tells the browser to apply a style when focus is on any child element of a specified element. Returning to the menu example, by setting &lt;code&gt;:focus-within&lt;/code&gt; on the menu element, you can make sure it stays visible when a menu item has focus:&lt;/p&gt;
&lt;div&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;.menu:focus-within&lt;/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;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;visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; visible&lt;span 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&gt;&lt;img alt=&quot;An illustration showing the difference in behavior between focus and focus-within.&quot; decoding=&quot;async&quot; height=&quot;559&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/NmLEz3wQMUv0QYIuhv2c.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Try tabbing through the focusable elements in the demo below. You&#39;ll notice that the menus remain visible as you focus on the menu items:&lt;/p&gt;
&lt;iframe height=&quot;275&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Simple CSS Dropdown Menu with Hover and :focus-within and Focus states&quot; src=&quot;https://codepen.io/una/embed/RMmogp?height=265&amp;theme-id=dark&amp;default-tab=result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/una/pen/RMmogp&quot;&gt;Simple CSS Dropdown Menu with Hover and :focus-within and Focus states&lt;/a&gt; by Una Kravets
  (&lt;a href=&quot;https://codepen.io/una&quot;&gt;@una&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;h2 id=&quot;media-queries-level-5&quot;&gt;Media Queries Level 5 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#media-queries-level-5&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/mediaqueries-5/#environment-blending&quot; rel=&quot;noopener&quot;&gt;New media queries&lt;/a&gt; give us powerful ways to adjust the user experience of our apps based on a user&#39;s device preferences. Basically, the browser serves as a proxy for system-level preferences that we can respond to in our CSS using the &lt;code&gt;prefers-*&lt;/code&gt; group of media queries:&lt;/p&gt;
&lt;img alt=&quot;A diagram showing media queries interpreting system-level user preferences.&quot; decoding=&quot;async&quot; height=&quot;400&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/f5Y9OhN3VMQz8nZMcZar.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Here are the new queries we think developers will be most excited about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/prefers-reduced-motion/&quot;&gt;prefers-reduced-motion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/prefers-color-scheme/&quot;&gt;prefers-color-scheme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@media/prefers-contrast&quot; rel=&quot;noopener&quot;&gt;prefers-contrast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/mediaqueries-5/#prefers-reduced-transparency&quot; rel=&quot;noopener&quot;&gt;prefers-reduced-transparency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@media/forced-colors&quot; rel=&quot;noopener&quot;&gt;forced-colors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@media/inverted-colors&quot; rel=&quot;noopener&quot;&gt;inverted-colors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These queries are a huge win for accessibility. Previously we had no way to know, for example, that a user had set their OS to high-contrast mode. If you wanted to provide a high-contrast mode for a web app that remained true to your brand, you had to ask users to choose it from UI within your app. Now you can detect the high-contrast setting from the OS using &lt;code&gt;prefers-contrast&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One exciting implication of these media queries is that we can design for multiple combinations of system-level user preferences to accommodate the wide range of user preferences and accessibility needs. If a user wants high-contrast dark mode when in dimly lit environments, you can do that!&lt;/p&gt;
&lt;p&gt;It&#39;s important to Adam that &amp;quot;prefers reduced motion&amp;quot; doesn&#39;t get implemented as &amp;quot;no motion.&amp;quot; The user is saying they prefer less motion, not that they don&#39;t want any animation. He asserts reduced motion is not no motion. Here&#39;s an example that uses a crossfade animation when the user prefers reduced motion:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/reduced-motion.webm&quot; type=&quot;video/webm; codecs=vp8&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/reduced-motion.mp4&quot; type=&quot;video/mp4; codecs=h264&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; In Chrome Canary, you can test CSS that uses &lt;code&gt;prefers-reduced-motion&lt;/code&gt; or &lt;code&gt;prefers-color-scheme&lt;/code&gt; by choosing the appropriate settings in the DevTools &lt;strong&gt;Rendering&lt;/strong&gt; drawer. To access &lt;strong&gt;Rendering&lt;/strong&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/devtools/command-menu/&quot;&gt;open the Command Menu&lt;/a&gt; and run the &lt;code&gt;Show Rendering&lt;/code&gt; command. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;logical-properties&quot;&gt;Logical properties &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#logical-properties&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Logical_Properties&quot; rel=&quot;noopener&quot;&gt;Logical properties&lt;/a&gt; solve a problem that has gained visibility as more developers tackle internationalization. Many layout properties like &lt;code&gt;margin&lt;/code&gt; and &lt;code&gt;padding&lt;/code&gt; assume a language that is read top-to-bottom and left-to-right.&lt;/p&gt;
&lt;img alt=&quot;A diagram showing traditional CSS layout properties.&quot; decoding=&quot;async&quot; height=&quot;559&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/mLz4eB2iG7yGUJ92DA0D.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;When designing pages for multiple languages with varying writing modes, developers have had to adjust all those properties individually across multiple elements, which quickly becomes a maintainability nightmare.&lt;/p&gt;
&lt;p&gt;Logical properties let you maintain layout integrity across translations and writing modes. They dynamically update based on the semantic ordering of content rather than its spatial arrangement. With logical properties, each element has two dimensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;block&lt;/strong&gt; dimension is &lt;strong&gt;perpendicular&lt;/strong&gt; to the flow of text in a line. (In English, &lt;code&gt;block-size&lt;/code&gt; is the same as &lt;code&gt;height&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;inline&lt;/strong&gt; dimension is &lt;strong&gt;parallel&lt;/strong&gt; to the flow of text in a line. (In English, &lt;code&gt;inline-size&lt;/code&gt; is the same as &lt;code&gt;width&lt;/code&gt;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These dimension names apply to all logical layout properties. So, for example, in English, &lt;code&gt;block-start&lt;/code&gt; is the same as &lt;code&gt;top&lt;/code&gt;, and &lt;code&gt;inline-end&lt;/code&gt; is the same as &lt;code&gt;right&lt;/code&gt;.&lt;/p&gt;
&lt;img alt=&quot;A diagram showing new CSS logical layout properties.&quot; decoding=&quot;async&quot; height=&quot;559&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/NcIz3jADhMnRMqRTUPKr.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;With logical properties, you can automatically update your layout for other languages by simply changing the &lt;code&gt;writing-mode&lt;/code&gt; and &lt;code&gt;direction&lt;/code&gt; properties for your page rather than updating dozens of layout properties on individual elements.&lt;/p&gt;
&lt;p&gt;You can see how logical properties work in the demo below by setting the &lt;code&gt;writing-mode&lt;/code&gt; property on the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element to different values:&lt;/p&gt;
&lt;iframe height=&quot;750&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Logical Properties Demo&quot; src=&quot;https://codepen.io/una/embed/mddxpaY?height=265&amp;theme-id=dark&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/una/pen/mddxpaY&quot;&gt;Logical Properties Demo&lt;/a&gt; by Una Kravets
  (&lt;a href=&quot;https://codepen.io/una&quot;&gt;@una&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;h2 id=&quot;position-sticky&quot;&gt;&lt;code&gt;position: sticky&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#position-sticky&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An element with &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/position#Sticky_positioning&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;position: sticky&lt;/code&gt;&lt;/a&gt; remains in block flow until it starts to go offscreen,
at which point it stops scrolling with the rest of the page
and sticks to the position specified by the element&#39;s &lt;code&gt;top&lt;/code&gt; value.
The space allocated for that element remains in the flow,
and the element returns to it when the user scrolls back up.&lt;/p&gt;
&lt;p&gt;Sticky positioning lets you create many useful effects that previously required JavaScript. To show some of the possibilities, we&#39;ve created several demos. Each demo uses largely the same CSS and only slightly adjusts the HTML markup to create each effect.&lt;/p&gt;
&lt;h3 id=&quot;sticky-stack&quot;&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/YzzZyMx&quot; rel=&quot;noopener&quot;&gt;Sticky Stack&lt;/a&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#sticky-stack&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this demo, all sticky elements share the same container. That means that each sticky element slides over the previous one as the user scrolls down. The sticky elements share the same stuck position.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-stack.webm&quot; type=&quot;video/webm; codecs=vp8&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-stack.mp4&quot; type=&quot;video/mp4; codecs=h264&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;sticky-slide&quot;&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/abbJOjP&quot; rel=&quot;noopener&quot;&gt;Sticky Slide&lt;/a&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#sticky-slide&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here, the sticky elements are cousins. (That is, their parents are siblings.) When a sticky element hits the lower boundary of its container, it moves up with the container, creating the impression that lower sticky elements are pushing up higher ones. In other words, they appear to compete for the stuck position.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-slide.webm&quot; type=&quot;video/webm; codecs=vp8&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-slide.mp4&quot; type=&quot;video/mp4; codecs=h264&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;sticky-desperado&quot;&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/qBBrbyx&quot; rel=&quot;noopener&quot;&gt;Sticky Desperado&lt;/a&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#sticky-desperado&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like Sticky Slide, the sticky elements in this demo are cousins. However, they&#39;ve been placed in containers set to a two-column grid layout.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-desperado.webm&quot; type=&quot;video/webm; codecs=vp8&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/sticky-desperado.mp4&quot; type=&quot;video/mp4; codecs=h264&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;backdrop-filter&quot;&gt;&lt;code&gt;backdrop-filter&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#backdrop-filter&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/backdrop-filter&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;backdrop-filter&lt;/code&gt;&lt;/a&gt; property lets you apply graphical effects to the area &lt;em&gt;behind&lt;/em&gt; an element rather than to the element itself. This makes lots of cool effects that were previously only achievable using complicated CSS and JavaScript hacks doable with one line of CSS.&lt;/p&gt;
&lt;p&gt;For example, this demo uses &lt;code&gt;backdrop-filter&lt;/code&gt; to achieve OS-style blurring:&lt;/p&gt;
&lt;iframe height=&quot;510&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;mddjjor&quot; src=&quot;https://codepen.io/una/embed/mddjjor?height=265&amp;theme-id=dark&amp;default-tab=result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/una/pen/mddjjor&quot;&gt;mddjjor&lt;/a&gt; by Una Kravets
  (&lt;a href=&quot;https://codepen.io/una&quot;&gt;@una&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;We already have a &lt;a href=&quot;https://web.dev/backdrop-filter/&quot;&gt;great post about &lt;code&gt;backdrop-filter&lt;/code&gt;&lt;/a&gt;, so head there for more info.&lt;/p&gt;
&lt;h2 id=&quot;is&quot;&gt;&lt;code&gt;:is()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#is&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/:is&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;:is()&lt;/code&gt; pseudo-class&lt;/a&gt; is actually over ten years old, it still doesn&#39;t see as much use as we think it deserves. It takes a comma-separated list of selectors as its argument and matches any selectors in that list. That flexibility makes it incredibly handy and can significantly reduce the amount of CSS you ship.&lt;/p&gt;
&lt;p&gt;Here&#39;s a quick example:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/is-animation.webm&quot; type=&quot;video/webm; codecs=vp8&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/next-gen-css-2019/is-animation.mp4&quot; type=&quot;video/mp4; codecs=h264&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;div&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.focus,&lt;br /&gt;button:focus&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;br /&gt;&lt;span class=&quot;token selector&quot;&gt;article &gt; h1,&lt;br /&gt;article &gt; h2,&lt;br /&gt;article &gt; h3,&lt;br /&gt;article &gt; h4,&lt;br /&gt;article &gt; h5,&lt;br /&gt;article &gt; h6&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;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* selects the same elements as the code above */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;button:is(.focus, :focus)&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;br /&gt;&lt;span class=&quot;token selector&quot;&gt;article &gt; :is(h1,h2,h3,h4,h5,h6)&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;gap&quot;&gt;&lt;code&gt;gap&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#gap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Grid_Layout&quot; rel=&quot;noopener&quot;&gt;CSS grid layout&lt;/a&gt; has had &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/gap&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;gap&lt;/code&gt;&lt;/a&gt; (previously &lt;code&gt;grid-gap&lt;/code&gt;) for some time. By specifying the internal spacing of a containing element rather than the spacing around child elements, &lt;code&gt;gap&lt;/code&gt; solves many common layout issues. For example, with gap, you don&#39;t have to worry about margins on child elements causing unwanted whitespace around the edges of a containing element:&lt;/p&gt;
&lt;img alt=&quot;Illustration showing how the gap property avoids unintended spacing around edges of a container element.&quot; decoding=&quot;async&quot; height=&quot;846&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Jzlzz2MdQmMGudZxcvZk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Even better news: &lt;code&gt;gap&lt;/code&gt; is coming to flexbox, bringing all the same spacing perks that grid has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There&#39;s one spacing declaration rather than many.&lt;/li&gt;
&lt;li&gt;There&#39;s no need to establish conventions for your project about which child elements should own spacing—the containing element owns the spacing instead.&lt;/li&gt;
&lt;li&gt;The code is more easily understandable than older strategies like the &lt;a href=&quot;https://alistapart.com/article/axiomatic-css-and-lobotomized-owls/&quot; rel=&quot;noopener&quot;&gt;lobotomized owl&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following video shows the benefits of using a single &lt;code&gt;gap&lt;/code&gt; property for two elements, one with a grid layout and one with a flex layout:&lt;/p&gt;
&lt;p&gt;Right now, only FireFox supports &lt;code&gt;gap&lt;/code&gt; in flex layouts, but play around with this demo to see how it works:&lt;/p&gt;
&lt;iframe height=&quot;600&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Gappy&quot; src=&quot;https://codepen.io/argyleink/embed/abbVqEv?height=265&amp;theme-id=dark&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/argyleink/pen/abbVqEv&quot;&gt;Gappy&lt;/a&gt; by Adam Argyle
  (&lt;a href=&quot;https://codepen.io/argyleink&quot;&gt;@argyleink&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;h2 id=&quot;css-houdini&quot;&gt;CSS Houdini &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#css-houdini&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Houdini&quot; rel=&quot;noopener&quot;&gt;Houdini&lt;/a&gt; is a set of low-level APIs for the browser&#39;s rendering engine that lets you tell the browser how to interpret custom CSS. In other words, it gives you access to the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CSS_Object_Model&quot; rel=&quot;noopener&quot;&gt;CSS Object Model&lt;/a&gt;, letting you &lt;em&gt;extend&lt;/em&gt; CSS via JavaScript. This has several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It gives you much more power to create custom CSS features.&lt;/li&gt;
&lt;li&gt;It&#39;s easier to separate rendering concerns from application logic.&lt;/li&gt;
&lt;li&gt;It&#39;s more performant than the CSS polyfilling we currently do with JavaScript since the browser will no longer have to parse scripts and do a second rendering cycle; Houdini code is parsed in the first rendering cycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Illustration showing how Houdini works compared to traditional JavaScript polyfills.&quot; decoding=&quot;async&quot; height=&quot;599&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Lh9zGq0HWW4amjfHbpRQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Houdini is an umbrella name for &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Houdini#The_Houdini_APIs&quot; rel=&quot;noopener&quot;&gt;several APIs&lt;/a&gt;. If you want more information about them and their current status, take a look at &lt;a href=&quot;https://ishoudinireadyyet.com/&quot; rel=&quot;noopener&quot;&gt;Is Houdini Ready Yet?&lt;/a&gt; In our talk, we covered the Properties and Values API, the Paint API, and the Animation Worklet because they&#39;re currently the most supported. We could easily dedicate a full post to each of these exciting APIs, but, for now, check out our talk for an overview and some cool demos that start to give a sense of what you can do with the APIs.&lt;/p&gt;
&lt;h2 id=&quot;overflow&quot;&gt;Overflow &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/next-gen-css-2019/#overflow&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a few more things on the horizon that we wanted to discuss but didn&#39;t have time to cover in depth, so we ran through them in a speed round.⚡ If you haven&#39;t heard of some of these features yet, be sure to watch &lt;a href=&quot;https://youtu.be/-oyeaIirVC0?t=1825&quot; rel=&quot;noopener&quot;&gt;the last part of the talk&lt;/a&gt;!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt;: a property that will allow you to set height and width at the same time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio&lt;/code&gt;: a property that sets an aspect ratio for elements that don&#39;t have one intrinsically&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;, and &lt;code&gt;clamp()&lt;/code&gt;: functions that will let you set numeric constraints on any CSS property, not just width and height&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list-style-type&lt;/code&gt; an existing property, but it will soon support a wider range of values, including emoji and SVGs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display: outer inner&lt;/code&gt;: The &lt;code&gt;display&lt;/code&gt; property will soon accept two parameters, which will let you explicitly specify its outer and inner layouts rather than using compound keywords like &lt;code&gt;inline-flex&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;CSS regions: will let you fill a specified, non-rectangular area that content can flow into and out of&lt;/li&gt;
&lt;li&gt;CSS modules: JavaScript will be able to request a CSS module and get a rich object back that&#39;s easy to perform operations on&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Adam Argyle</name>
    </author><author>
      <name>Una Kravets</name>
    </author>
  </entry>
</feed>
