<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>web.dev</title>
  <subtitle>Let&#39;s build the future of the web.</subtitle>
  <link href="https://web.dev/feed.xml" rel="self"/>
  <link href="https://web.dev"/>
  <updated>2023-01-13T02:40:27Z</updated>
  <id>https://web.dev/</id>
  <author>
    <name>Google Developers</name>
  </author>
  <icon>https://web.dev/images/social.png</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  
    
    
    <entry>
      <title>All of Learn Accessibility! is available</title>
      <link href="https://web.dev/learn-accessibility-available/"/>
      <updated>2023-01-12T00:00:00Z</updated>
      <id>https://web.dev/learn-accessibility-available/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;All modules in the &lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility&lt;/a&gt; course are now
available. Written by &lt;a href=&quot;https://twitter.com/cariefisher&quot; rel=&quot;noopener&quot;&gt;Carie Fisher&lt;/a&gt;, these
courses take you through the essentials for building accessible websites and
web apps.&lt;/p&gt;
&lt;p&gt;You can read them in whatever order you&#39;d like. The final modules on testing
walk you through a culmination of all of your knowledge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/learn/accessibility/test-automated&quot;&gt;Automated testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/learn/accessibility/test-manual&quot;&gt;Manual accessibility testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/learn/accessibility/test-assistive-technology&quot;&gt;Assistive technology testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last new module will teach you how to make your
&lt;a href=&quot;https://web.dev/learn/accessibility/forms&quot;&gt;forms more accessible&lt;/a&gt;. This is a great complement
to &lt;a href=&quot;https://web.dev/learn/forms/&quot;&gt;Learn Forms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And that&#39;s not all. We had four community spotlights with people working on
accessibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-melanie/&quot;&gt;Melanie Sumner&lt;/a&gt; told us about her journey
into engineering, accessible design, Ember.js, and the importance of funding
these efforts.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-shuyi/&quot;&gt;Olutimilehin Olushuyi&lt;/a&gt; told us about his move
from the law to web development, building accessible communities, and creating
accessible layouts.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-albert-kim/&quot;&gt;Albert Kim&lt;/a&gt; told us about mental health
awareness, building for invisible disabilities, the COGA Accessibility
Community Group, and more practical wisdom.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-elisa/&quot;&gt;Elisa Bandy&lt;/a&gt; told us about her work for
Google&#39;s internal documentation, how to prioritize use cases, and building
expertise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We hope you&#39;ll discover some new best practices. These modules are meant to
build your expertise, but some accessibility best practices differ, based on
the disability you&#39;re addressing.&lt;/p&gt;
&lt;p&gt;We remain open to your feedback. &lt;a href=&quot;https://github.com/GoogleChrome/web.dev/issues/new/choose&quot; rel=&quot;noopener&quot;&gt;Open a GitHub issue&lt;/a&gt;
and give as much information as you can so we can address your questions or concerns.&lt;/p&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Our top Core Web Vitals recommendations for 2023</title>
      <link href="https://web.dev/top-cwv-2023/"/>
      <updated>2023-01-10T00:00:00Z</updated>
      <id>https://web.dev/top-cwv-2023/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;Over the years, we at Google have made a lot of recommendations to web developers on how to improve performance.&lt;/p&gt;
&lt;p&gt;While each of these recommendations, individually, may improve performance for many sites, the full set of recommendations is admittedly overwhelming and, realistically, there&#39;s no way any one person or site could follow all of them.&lt;/p&gt;
&lt;p&gt;Unless web performance is your day job, it&#39;s probably not obvious which recommendations are going to have the largest positive impact on your site. For example, you might have read that implementing critical CSS can improve load performance, and you may have also heard that it&#39;s important to optimize your images. But, if you don&#39;t have time to work on both things, how would you decide which one to pick?&lt;/p&gt;
&lt;p&gt;On the Chrome team, we&#39;ve spent the last year trying to answer this question: &lt;em&gt;what are the most important recommendations we can give to developers to help them improve performance for their users?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To adequately answer this question we have to consider not just the technical merits of any given recommendation, but also human and organizational factors that influence the likelihood that developers will actually be able to adopt these recommendations. In other words, some recommendations may be hugely impactful in theory, but in reality very few sites will have the time or resources to implement them. Similarly, some recommendations are critical, but most websites are already following these practices.&lt;/p&gt;
&lt;p&gt;In short, we wanted our list of top web performance recommendations to focus on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recommendations we believe will have the &lt;strong&gt;largest real-world impact&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Recommendations that are &lt;strong&gt;relevant and applicable to most sites&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Recommendations that are &lt;strong&gt;realistic for most developers to implement&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the past year we&#39;ve spent a lot of time auditing the full set of performance recommendations we make, and assessing each of them (both qualitatively and quantitatively) against the above three criteria.&lt;/p&gt;
&lt;p&gt;This post outlines our top recommendations to improve performance for each of the &lt;a href=&quot;https://web.dev/vitals/#core-web-vitals&quot;&gt;Core Web Vitals&lt;/a&gt; metrics. If you&#39;re new to web performance, or if you&#39;re trying to decide what will give you the biggest bang for your buck, we think these recommendations are the best place to start.&lt;/p&gt;
&lt;h2 id=&quot;largest-contentful-paint-lcp&quot;&gt;Largest Contentful Paint (LCP) &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our first set of recommendations are for &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt;, which is a measure of load performance. Of the three Core Web Vitals metrics, LCP is the one that the largest number of sites struggle with—only &lt;a href=&quot;https://datastudio.google.com/s/nw4gcbKA5o4&quot; rel=&quot;noopener&quot;&gt;about half&lt;/a&gt; of all sites on the web today meet the &lt;a href=&quot;https://web.dev/lcp/#what-is-a-good-lcp-score&quot;&gt;recommended threshold&lt;/a&gt;—so let&#39;s start there.&lt;/p&gt;
&lt;h3 id=&quot;ensure-the-lcp-resource-is-discoverable-from-the-html-source&quot;&gt;Ensure the LCP resource is discoverable from the HTML source &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#ensure-the-lcp-resource-is-discoverable-from-the-html-source&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://almanac.httparchive.org/en/2022/&quot; rel=&quot;noopener&quot;&gt;2022 Web Almanac&lt;/a&gt; by HTTP Archive, &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#fig-8&quot; rel=&quot;noopener&quot;&gt;72%&lt;/a&gt; of mobile pages have an image as their LCP element, which means that for most sites to optimize their LCP, they&#39;ll need to ensure those images can load quickly.&lt;/p&gt;
&lt;p&gt;What may not be obvious to many developers is that the time it takes to load an image is just one part of the challenge. Another critical part is the time &lt;em&gt;before&lt;/em&gt; an image starts loading, and HTTP Archive data suggests that&#39;s actually where many sites get tripped up.&lt;/p&gt;
&lt;p&gt;In fact, of the pages where the LCP element was an image, &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#lcp-static-discoverability&quot; rel=&quot;noopener&quot;&gt;39%&lt;/a&gt; of those images had source URLs that were not &lt;a href=&quot;https://web.dev/optimize-lcp/#optimize-when-the-resource-is-discovered&quot;&gt;discoverable&lt;/a&gt; from the HTML document source. In other words, those URLs were not found in standard HTML attributes (such as &lt;code&gt;&amp;lt;img src=&amp;quot;...&amp;quot;&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot; href=&amp;quot;...&amp;quot;&amp;gt;&lt;/code&gt;), which would allow the browser to quickly discover them and start loading them right away.&lt;/p&gt;
&lt;p&gt;If a page needs to wait for CSS or JavaScript files to be fully downloaded, parsed, and processed before the image can even start loading, it may already be too late.&lt;/p&gt;
&lt;p&gt;As a general rule, if your LCP element is an image, the image&#39;s URL should always be discoverable from the HTML source. Some tips to make that possible are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load the image using an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element with the &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;srcset&lt;/code&gt; attribute.&lt;/strong&gt; Do not use non-standard attributes like &lt;code&gt;data-src&lt;/code&gt; that require JavaScript in order to render, as that will always be slower. &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#lcp-lazy-loading&quot; rel=&quot;noopener&quot;&gt;9%&lt;/a&gt; of pages obscure their LCP image behind &lt;code&gt;data-src&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prefer server-side rendering (SSR) over client-side rendering (CSR),&lt;/strong&gt; as SSR implies that the full page markup (including the image) is present in the HTML source. CSR solutions require JavaScript to run before the image can be discovered.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If your image needs to be referenced from an external CSS or JS file, you can still include it in the HTML source via a &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; tag.&lt;/strong&gt; Note that images referenced by inline styles are not discoverable by the browser&#39;s &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;preload scanner&lt;/a&gt;, so even though they&#39;re found in the HTML source, discovery of them might still be blocked on the loading of other resources, so preloading can help in these cases.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To help you understand if your LCP image has discoverability problems, Lighthouse will be releasing a &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse/issues/13738&quot; rel=&quot;noopener&quot;&gt;new audit&lt;/a&gt; in version 10.0 (expected January 2023).&lt;/p&gt;
&lt;p&gt;Ensuring the LCP resource is discoverable from the HTML source can lead to measurable improvements and it also unlocks additional opportunities to prioritize the resource, which is our next recommendation.&lt;/p&gt;
&lt;h3 id=&quot;ensure-the-lcp-resource-is-prioritized&quot;&gt;Ensure the LCP resource is prioritized &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#ensure-the-lcp-resource-is-prioritized&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Making sure the LCP resource can be discovered from the HTML source is a critical first step in ensuring the LCP resource can start loading early, but another important step is ensuring that the loading of that resource is &lt;a href=&quot;https://web.dev/optimize-lcp/#optimize-the-priority-the-resource-is-given&quot;&gt;prioritized&lt;/a&gt; and doesn&#39;t get queued behind a bunch of other, less important resources.&lt;/p&gt;
&lt;p&gt;For example, even if your LCP image is present in the HTML source using a standard &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, if your page includes a dozen &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your document before that &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, it may be a while before your image resource starts loading.&lt;/p&gt;
&lt;p&gt;The easiest way to solve this problem is to provide a hint to the browser about what resources are the highest priority by setting the new &lt;a href=&quot;https://web.dev/priority-hints/&quot;&gt;&lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;/a&gt; attribute on the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag that loads your LCP image. This instructs the browser to load it earlier, rather than waiting for those scripts to complete.&lt;/p&gt;
&lt;p&gt;According to the Web Almanac, only &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#lcp-prioritization&quot; rel=&quot;noopener&quot;&gt;0.03%&lt;/a&gt; of eligible pages are taking advantage of this new API, meaning there is plenty of opportunity for most sites on the web to improve LCP with very little work. While the &lt;code&gt;fetchpriority&lt;/code&gt; attribute is currently only supported in Chromium-based browsers, this API is a progressive enhancement that other browsers just ignore, so we strongly recommend developers use it now.&lt;/p&gt;
&lt;p&gt;For non-Chromium browsers, the only way to ensure the LCP resource is prioritized above other resources is to reference it earlier in the document. Using the example again of a site with lots of &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the document, if you wanted to ensure your LCP resource was prioritized ahead of those script resources, you could add a &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; tag before any of those scripts, or you could move those scripts to below the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; later in the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. While this works, it&#39;s less ergonomic than using &lt;code&gt;fetchpriority&lt;/code&gt;, so we hope other browsers add support soon.&lt;/p&gt;
&lt;p&gt;Another critical aspect of prioritizing the LCP resource is to ensure you don&#39;t do anything that causes it to be &lt;strong&gt;deprioritized&lt;/strong&gt;, such as adding the &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; attribute. Today, &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#lcp-lazy-loading&quot; rel=&quot;noopener&quot;&gt;10%&lt;/a&gt; of pages actually set &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; on their LCP image. Beware of image optimization solutions that indiscriminately apply lazy-loading behavior to all images. If they provide a way to override that behavior, be sure to use it for the LCP image. If you&#39;re not sure which image will be the LCP, try using heuristics to pick a reasonable candidate.&lt;/p&gt;
&lt;p&gt;Deferring non-critical resources is another way to effectively boost the relative priority of the LCP resource. For example, scripts that are not powering the user interface (like analytics scripts or social widgets) can be safely postponed until after the &lt;code&gt;load&lt;/code&gt; event fires, which ensures they won&#39;t compete with other critical resources (such as the LCP resource) for network bandwidth.&lt;/p&gt;
&lt;p&gt;To summarize, you should follow these best practices to ensure that the LCP resource is loaded early, and at high priority:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; to the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag of your LCP image.&lt;/strong&gt; If the LCP resource is loaded via a&lt;code&gt; &amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; tag, fear not because you can also set &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; on that!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never set &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; on the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag of your LCP image.&lt;/strong&gt; Doing this will deprioritize your image and delay when it starts loading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Defer non-critical resources when possible.&lt;/strong&gt; Either by moving them to the end of your document, using native lazy-loading for &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/&quot;&gt;images&lt;/a&gt; or &lt;a href=&quot;https://web.dev/iframe-lazy-loading/&quot;&gt;iframes&lt;/a&gt;, or loading them asynchronously via JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;use-a-cdn-to-optimize-document-and-resource-ttfb&quot;&gt;Use a CDN to optimize document and resource TTFB &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#use-a-cdn-to-optimize-document-and-resource-ttfb&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The previous two recommendations focused on making sure your LCP resource is discovered early and prioritized so it can start loading right away. The final piece to this puzzle is making sure the initial document response arrives as quickly as possible too.&lt;/p&gt;
&lt;p&gt;The browser cannot start loading any subresources until it receives the first byte of the initial HTML document response, and the sooner that happens, the sooner everything else can start happening as well.&lt;/p&gt;
&lt;p&gt;This time is known as &lt;a href=&quot;https://web.dev/ttfb/&quot;&gt;Time to First Byte (TTFB)&lt;/a&gt;, and the best way to reduce TTFB is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serve your content as geographically close to your users as possible&lt;/li&gt;
&lt;li&gt;Cache that content so recently-requested content can be served again quickly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best way to do both of these things is to &lt;a href=&quot;https://web.dev/content-delivery-networks/&quot;&gt;use a CDN&lt;/a&gt;. CDNs distribute your resources to edge servers, which are spread across the globe, thus limiting the distance those resources have to travel over the wire to your users. CDNs also usually have fine-grained caching controls that can be customized and optimized for your site&#39;s needs.&lt;/p&gt;
&lt;p&gt;Many developers are familiar with using a CDN to host static assets, but CDNs can serve and cache HTML documents as well, even those that are dynamically generated.&lt;/p&gt;
&lt;p&gt;According to the Web Almanac, only &lt;a href=&quot;https://almanac.httparchive.org/en/2022/cdn#cdn-adoption&quot; rel=&quot;noopener&quot;&gt;29%&lt;/a&gt; of HTML document requests were served from a CDN, which means there is significant opportunity for sites to claim additional savings.&lt;/p&gt;
&lt;p&gt;Some tips for configuring your CDNs are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider increasing how long content is cached for (for example, is it actually critical that content is always fresh? Or can it be a few minutes stale?).&lt;/li&gt;
&lt;li&gt;Consider maybe even caching content indefinitely, and then purging the cache if/when you make an update.&lt;/li&gt;
&lt;li&gt;Explore whether you can move dynamic logic currently running on your origin server to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Edge_computing&quot; rel=&quot;noopener&quot;&gt;edge&lt;/a&gt; (a feature of most modern CDNs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, any time you can serve content directly from the edge (avoiding a trip to your origin server) it&#39;s a performance win. And even in cases where you &lt;em&gt;do&lt;/em&gt; have to make the journey all the way back to your origin server, CDNs are generally optimized to do that much more quickly, so it&#39;s a win either way.&lt;/p&gt;
&lt;h2 id=&quot;cumulative-layout-shift-cls&quot;&gt;Cumulative Layout Shift (CLS) &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#cumulative-layout-shift-cls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next set of recommendations are for &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt;, which is a measure of visual stability on web pages. While CLS has &lt;a href=&quot;https://datastudio.google.com/s/gFjrTptD140&quot; rel=&quot;noopener&quot;&gt;improved a lot&lt;/a&gt; on the web since 2020, about a quarter of websites still do not meet the &lt;a href=&quot;https://web.dev/cls/#what-is-a-good-cls-score&quot;&gt;recommended threshold&lt;/a&gt;, so there remains a big opportunity for many sites to improve their user experience.&lt;/p&gt;
&lt;h3 id=&quot;set-explicit-sizes-on-any-content-loaded-from-the-page&quot;&gt;Set explicit sizes on any content loaded from the page &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#set-explicit-sizes-on-any-content-loaded-from-the-page&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/cls/#layout-shifts-in-detail&quot;&gt;Layout shifts&lt;/a&gt; usually happen when existing content moves after other content finishes loading. Therefore, the primary way to mitigate this is to reserve any required space in advance as much as possible.&lt;/p&gt;
&lt;p&gt;The most straightforward way to fix layout shifts caused by unsized images is to &lt;strong&gt;explicitly set &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes&lt;/strong&gt; (or equivalent CSS properties). However, according to HTTP Archive, &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#explicit-dimensions&quot; rel=&quot;noopener&quot;&gt;72%&lt;/a&gt; of pages have at least one unsized image. Without an explicit size, browsers will initially set a default height of &lt;code&gt;0px&lt;/code&gt; and may cause a noticeable layout shift when the image is finally loaded and the dimensions are discovered. This represents both a huge opportunity for the collective web—and that opportunity requires much less effort than some of the other recommendations suggested in this article.&lt;/p&gt;
&lt;p&gt;It&#39;s also important to keep in mind that images are not the only contributors to CLS. Layout shifts may be caused by other content that typically loads in after the page is initially rendered, including third-party ads or embedded videos. The &lt;a href=&quot;https://web.dev/aspect-ratio/&quot;&gt;&lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/a&gt; property can help combat this. It&#39;s a relatively new CSS feature that allows developers to explicitly provide an aspect ratio to images as well as non-image elements. This will allow you to set a dynamic  &lt;code&gt;width&lt;/code&gt; (for example based on screen size), and have the browser automatically calculate the appropriate height, in much the same way as they do for images with dimensions.&lt;/p&gt;
&lt;p&gt;Sometimes it&#39;s not possible to know the exact size of dynamic content since it is, by its very nature, dynamic. However, even if you don&#39;t know the exact size, you can still take steps to reduce the severity of layout shifts. &lt;strong&gt;Setting a sensible &lt;code&gt;min-height&lt;/code&gt;&lt;/strong&gt; is almost always better than allowing the browser to use the default height of &lt;code&gt;0px&lt;/code&gt; for an empty element. Using a &lt;code&gt;min-height&lt;/code&gt; is also usually an easy fix as it still allows the container to grow to the final content height if needed—it has just reduced that amount of growth from the full amount to a hopefully more tolerable level.&lt;/p&gt;
&lt;h3 id=&quot;ensure-pages-are-eligible-for-bfcache&quot;&gt;Ensure pages are eligible for bfcache &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#ensure-pages-are-eligible-for-bfcache&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Browsers use a navigation mechanism called the &lt;a href=&quot;https://web.dev/bfcache/&quot;&gt;back/forward cache&lt;/a&gt;—or bfcache for short—to instantly load a page from earlier or later in the browser history directly from a memory snapshot.&lt;/p&gt;
&lt;p&gt;The bfcache is a significant browser-level performance optimization, and it entirely eliminates the layout shifts during page load, which for many sites is where most of their CLS occurs. The introduction of the bfcache caused &lt;a href=&quot;https://twitter.com/anniesullie/status/1491399685961293828?s=20&amp;amp;t=k7JgTjdO21uMpeOuOofroA&quot; rel=&quot;noopener&quot;&gt;the biggest improvement in CLS&lt;/a&gt; that we saw in 2022.&lt;/p&gt;
&lt;p&gt;Despite this, &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#bfcache-eligibility&quot; rel=&quot;noopener&quot;&gt;a significant number of websites&lt;/a&gt; are ineligible for the bfcache and so are missing out on this free web performance win for a significant number of navigations. Unless your page is loading sensitive information that you don&#39;t want to be restored from memory, you&#39;ll want to make sure that your pages are eligible.&lt;/p&gt;
&lt;p&gt;Site owners should check that their pages are &lt;a href=&quot;https://web.dev/bfcache/#optimize-your-pages-for-bfcache&quot;&gt;eligible for the bfcache&lt;/a&gt; and work on any reasons why they are not. Chrome already &lt;a href=&quot;https://web.dev/bfcache/#test-to-ensure-your-pages-are-cacheable&quot;&gt;has a bfcache tester in DevTools&lt;/a&gt; and this year we plan to enhance tooling here with &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse/issues/13960&quot; rel=&quot;noopener&quot;&gt;a new Lighthouse audit performing a similar test&lt;/a&gt; and &lt;a href=&quot;https://chromestatus.com/feature/5684908759449600&quot; rel=&quot;noopener&quot;&gt;an API to measure this in the field&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While we have included the bfcache in the CLS section, as we saw the biggest gains there so far, the bfcache will generally also improve other Core Web Vitals too. It is one of &lt;a href=&quot;https://calendar.perfplanet.com/2022/fast-is-good-instant-is-better/&quot; rel=&quot;noopener&quot;&gt;a number of instant navigations&lt;/a&gt; available to drastically improve page navigations.&lt;/p&gt;
&lt;h3 id=&quot;avoid-animationstransitions-that-use-layout-inducing-css-properties&quot;&gt;Avoid animations/transitions that use layout-inducing CSS properties &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#avoid-animationstransitions-that-use-layout-inducing-css-properties&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another common source of layout shifts is when elements are animated. For example, cookie banners or other notification banners that slide in from the top or bottom are often a contributor to CLS. This is particularly problematic when these banners push other content out of the way, but even when they don&#39;t, animating them can still impact CLS.&lt;/p&gt;
&lt;p&gt;While HTTP Archive data can&#39;t conclusively connect animations to layout shifts, the data does show that pages that animate any CSS property that &lt;em&gt;could&lt;/em&gt; affect layout are 15% less likely to have &amp;quot;good&amp;quot; CLS than pages overall. Some properties are associated with worse CLS than others. For instance, pages that animate &lt;code&gt;margin&lt;/code&gt; or &lt;code&gt;border&lt;/code&gt; widths have &amp;quot;poor&amp;quot; CLS at almost twice the rate that pages overall are assessed as poor.&lt;/p&gt;
&lt;p&gt;This is perhaps not surprising, because any time you transition or animate &lt;em&gt;any&lt;/em&gt; layout-inducing CSS property, it will result in &lt;a href=&quot;https://web.dev/cls/#layout-shifts-in-detail&quot;&gt;layout shifts&lt;/a&gt;, and if those layout shifts are not within 500 milliseconds of a user interaction, they will impact CLS.&lt;/p&gt;
&lt;p&gt;What may be surprising to some developers is that this is true even in cases where the element is taken outside of the normal document flow. For example, absolutely positioned elements that animate &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;left&lt;/code&gt; will cause layout shifts, even if they aren&#39;t pushing other content around. However, if instead of animating &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;left&lt;/code&gt; you animate &lt;code&gt;transform:translateX()&lt;/code&gt; or &lt;code&gt;transform:translateY()&lt;/code&gt;, it won&#39;t cause the browser to update page layout and thus won&#39;t produce any layout shifts.&lt;/p&gt;
&lt;p&gt;Preferring animation of CSS properties that can be updated on the browser&#39;s compositor thread has long been &lt;a href=&quot;https://web.dev/animations-guide/&quot;&gt;a performance best practice&lt;/a&gt; because it moves that work onto the GPU and off the main thread. And in addition to it being a general performance best practice, it can also help improve CLS.&lt;/p&gt;
&lt;p&gt;As a general rule, never animate or transition any CSS property that requires the browser to update the page layout, unless you&#39;re doing it in response to a user tap or key press (though &lt;a href=&quot;https://web.dev/cls/#user-initiated-layout-shifts&quot;&gt;not &lt;code&gt;hover&lt;/code&gt;&lt;/a&gt;). And whenever possible, prefer transitions and animations using the CSS &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; property.&lt;/p&gt;
&lt;p&gt;The Lighthouse audit &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/non-composited-animations/&quot; rel=&quot;noopener&quot;&gt;Avoid non-composited animations&lt;/a&gt; will warn when a page animates potentially slow CSS properties.&lt;/p&gt;
&lt;h2 id=&quot;first-input-delay-fid&quot;&gt;First Input Delay (FID) &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#first-input-delay-fid&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our last set of recommendations are for &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt;, which is a measure of a page&#39;s responsiveness to user interactions. While most sites on the web currently &lt;a href=&quot;https://datastudio.google.com/s/vax9YUKhRN0&quot; rel=&quot;noopener&quot;&gt;score very well&lt;/a&gt; on FID, we&#39;ve &lt;a href=&quot;https://web.dev/better-responsiveness-metric/#what-improvements-are-we-considering&quot;&gt;documented&lt;/a&gt; shortcomings of the FID metric in the past, and we believe there is still a lot of opportunity for sites to improve their overall responsiveness to user interactions.&lt;/p&gt;
&lt;p&gt;Our new &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; metric is a possible successor to FID, and all of the recommendations below apply equally well to both FID and INP. Given that sites &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#inp-as-a-hypothetical-cwv-metric&quot; rel=&quot;noopener&quot;&gt;perform worse&lt;/a&gt; on INP than FID, especially on mobile, we encourage developers to seriously consider these responsiveness recommendations, despite having &amp;quot;good&amp;quot; FID.&lt;/p&gt;
&lt;h3 id=&quot;avoid-or-break-up-long-tasks&quot;&gt;Avoid or break up long tasks &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#avoid-or-break-up-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tasks are any piece of discrete work that the browser does. Tasks include rendering, layout, parsing, and compiling and executing scripts. When tasks become &lt;a href=&quot;https://web.dev/long-tasks-devtools/#what-are-long-tasks&quot;&gt;long tasks&lt;/a&gt;—that is, 50 milliseconds or longer—they block the main thread from being able to respond quickly to user inputs.&lt;/p&gt;
&lt;p&gt;Per the Web Almanac, there&#39;s &lt;a href=&quot;https://almanac.httparchive.org/en/2022/javascript#long-tasksblocking-time&quot; rel=&quot;noopener&quot;&gt;plenty of evidence&lt;/a&gt; to suggest that developers could be doing more to avoid or break up long tasks. While breaking up long tasks may not be as low of an effort as other recommendations in this article, it&#39;s less effort than other techniques not offered in this article.&lt;/p&gt;
&lt;p&gt;While you should always strive to do as little work as possible in JavaScript, you can help the main thread quite a bit by &lt;a href=&quot;https://web.dev/optimize-long-tasks/&quot;&gt;breaking up long tasks into smaller ones&lt;/a&gt;. You can accomplish this by &lt;a href=&quot;https://web.dev/optimize-long-tasks/#use-asyncawait-to-create-yield-points&quot;&gt;yielding to the main thread&lt;/a&gt; often so that rendering updates and other user interactions can occur more quickly.&lt;/p&gt;
&lt;p&gt;Another option is to consider using APIs such as &lt;a href=&quot;https://web.dev/optimize-long-tasks/#yield-only-when-necessary&quot;&gt;&lt;code&gt;isInputPending&lt;/code&gt;&lt;/a&gt; and the &lt;a href=&quot;https://web.dev/optimize-long-tasks/#a-dedicated-scheduler-api&quot;&gt;Scheduler API&lt;/a&gt;. &lt;code&gt;isInputPending&lt;/code&gt; is a function that returns a boolean value that indicates whether a user input is pending. If it returns &lt;code&gt;true&lt;/code&gt;, you can yield to the main thread so it can handle the pending user input.&lt;/p&gt;
&lt;p&gt;The Scheduler API is a more advanced approach, which allows you to schedule work based on a system of priorities that take into account whether the work being done is user-visible or backgrounded.&lt;/p&gt;
&lt;p&gt;By breaking up long tasks, you&#39;re giving the browser more opportunities to fit in critical user-visible work, such as dealing with interactions and any resulting rendering updates.&lt;/p&gt;
&lt;h3 id=&quot;avoid-unnecessary-javascript&quot;&gt;Avoid unnecessary JavaScript &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#avoid-unnecessary-javascript&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There&#39;s no doubt about it: &lt;a href=&quot;https://almanac.httparchive.org/en/2022/javascript#how-much-javascript-do-we-load&quot; rel=&quot;noopener&quot;&gt;websites are shipping more JavaScript than ever before&lt;/a&gt;, and the trend doesn&#39;t look like it&#39;s changing any time soon. When you ship too much JavaScript, you&#39;re creating an environment where tasks are competing for the main thread&#39;s attention. This can definitely affect your website&#39;s responsiveness, especially during that crucial startup period.&lt;/p&gt;
&lt;p&gt;This is not an unsolvable problem, however. You do have some options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/coverage/&quot; rel=&quot;noopener&quot;&gt;coverage tool&lt;/a&gt; in Chrome DevTools to find unused code in your website&#39;s resources. By reducing the size of the resources you need during startup, you can ensure your website spends less time parsing and compiling code, which leads to a smoother initial user experience.&lt;/li&gt;
&lt;li&gt;Sometimes the unused code you find using the coverage tool is marked &amp;quot;unused&amp;quot; because it wasn&#39;t executed during startup, but is still necessary for some functionality in the future. This is code that you can move to a separate bundle via &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;code splitting&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you&#39;re using a tag manager, be sure to &lt;a href=&quot;https://web.dev/tag-best-practices/&quot;&gt;periodically check your tags to make sure they are optimized&lt;/a&gt;, or even if they&#39;re still being used. Older tags with unused code can be cleared out to make your tag manager&#39;s JavaScript smaller and more efficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;avoid-large-rendering-updates&quot;&gt;Avoid large rendering updates &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#avoid-large-rendering-updates&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript isn&#39;t the only thing that can affect your website&#39;s responsiveness. Rendering can be a type of expensive work in its own right—and when large rendering updates happen, they can interfere with your website&#39;s ability to respond to user inputs.&lt;/p&gt;
&lt;p&gt;Optimizing rendering work isn&#39;t a straightforward process, and it often depends on what you&#39;re trying to achieve. Even so, there are some things you can do to ensure that your rendering updates are reasonable, and don&#39;t sprawl into long tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;requestAnimationFrame()&lt;/code&gt;&lt;/a&gt; for doing any non-visual work. &lt;code&gt;requestAnimationFrame()&lt;/code&gt; calls are handled during the rendering phase of the event loop, and when too much work is done during this step, rendering updates can be delayed. It&#39;s essential that any work you&#39;re doing with &lt;code&gt;requestAnimationFrame()&lt;/code&gt; is reserved strictly for tasks that involve rendering updates.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/dom-size/&quot; rel=&quot;noopener&quot;&gt;Keep your DOM size small&lt;/a&gt;. DOM size and the intensity of layout work are correlated. When the renderer has to update the layout for a very large DOM, the work required to recalculate its layout can increase significantly.&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;Use CSS containment&lt;/a&gt;. CSS containment relies on the CSS &lt;code&gt;contain&lt;/code&gt; property, which gives instructions to the browser about how to do layout work for the container the &lt;code&gt;contain&lt;/code&gt; property is set on, including even isolating the scope of layout and rendering to a specific root in the DOM. It&#39;s not always an easy process, but by isolating areas containing complex layouts, you can avoid doing layout and rendering work for them that isn&#39;t necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/top-cwv-2023/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Improving page performance can seem like a daunting task, especially given that there is a mountain of guidance across the web to consider. By focusing on these recommendations, however, you can approach the problem with focus and purpose, and hopefully move the needle for your website&#39;s Core Web Vitals.&lt;/p&gt;
&lt;p&gt;While the recommendations listed here are by no means exhaustive, we do believe—based on careful analysis of the state of the web—that these recommendations are the most effective ways that sites can improve their Core Web Vitals performance in 2023.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to go beyond the recommendations listed here, check out these optimization guides for more information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-lcp/&quot;&gt;Optimize LCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-cls/&quot;&gt;Optimize CLS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/&quot;&gt;Optimize FID&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-inp/&quot;&gt;Optimize INP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s to a new year, and a faster web for all! May your sites be fast for your users in all the ways that matter most.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@devintavery&quot; rel=&quot;noopener&quot;&gt;Devin Avery&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Philip Walton</name>
        </author><author>
          <name>Rick Viscomi</name>
        </author><author>
          <name>Barry Pollard</name>
        </author><author>
          <name>Brendan Kenny</name>
        </author><author>
          <name>Jeremy Wagner</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>New to the web platform in December</title>
      <link href="https://web.dev/web-platform-12-2022/"/>
      <updated>2022-12-28T00:00:00Z</updated>
      <id>https://web.dev/web-platform-12-2022/</id>
      <content type="text/html" mode="escaped">&lt;h2 id=&quot;stable-browser-releases&quot;&gt;Stable browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#stable-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In December, &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/108&quot; rel=&quot;noopener&quot;&gt;Firefox 108&lt;/a&gt;, and &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-16_2-release-notes&quot; rel=&quot;noopener&quot;&gt;Safari 16.2&lt;/a&gt; became stable. Let&#39;s take a look at what this means for the web platform.&lt;/p&gt;
&lt;h3 id=&quot;support-for-height-and-width-attributes-of-lesssourcegreater&quot;&gt;Support for &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; attributes of &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#support-for-height-and-width-attributes-of-lesssourcegreater&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firefox 108 supports &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; attributes for the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/source&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt;&lt;/a&gt; element, when it is a child of a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element. These attributes accept the height or width of the image, in pixels, as an integer without a unit.&lt;/p&gt;
&lt;h3 id=&quot;trigonometric-css-functions&quot;&gt;Trigonometric CSS functions &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#trigonometric-css-functions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firefox also now supports trigonometric functions in CSS—&lt;code&gt;sin()&lt;/code&gt;, &lt;code&gt;cos()&lt;/code&gt;, &lt;code&gt;tan()&lt;/code&gt;, &lt;code&gt;asin()&lt;/code&gt;, &lt;code&gt;acos()&lt;/code&gt;, &lt;code&gt;atan()&lt;/code&gt;, and &lt;code&gt;atan2()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/sin#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h3 id=&quot;support-for-last-baseline-in-all-three-engines&quot;&gt;Support for last baseline in all three engines &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#support-for-last-baseline-in-all-three-engines&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to a number of CSS fixes, Safari 16.2 includes &lt;code&gt;last baseline&lt;/code&gt; alignment for CSS grid and flexbox layout, which means this feature now supported in the three main browser engines.&lt;/p&gt;
&lt;h3 id=&quot;css-font-variant-alternates&quot;&gt;CSS &lt;code&gt;font-variant-alternates&lt;/code&gt; &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#css-font-variant-alternates&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari also adds support for additional values for the &lt;code&gt;font-variant-alternates&lt;/code&gt; CSS property: annotation(value-name), character-variant(value-name), ornaments(value-name), styleset(value-name), stylistic(value-name), swash(value-name), along with the associated &lt;code&gt;@font-feature-values&lt;/code&gt; at-rule.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 34, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        34
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 9.1, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        9.1
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/font-variant-alternates#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;beta-browser-releases&quot;&gt;Beta browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#beta-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beta browser versions give you a preview of things that will be in the next stable version of the browser. It&#39;s a great time to test new features, or removals, that could impact your site before the world gets that release. New betas are &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/109&quot; rel=&quot;noopener&quot;&gt;Firefox 109&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-16_3-release-notes&quot; rel=&quot;noopener&quot;&gt;Safari 16.3&lt;/a&gt;, and &lt;a href=&quot;https://developer.chrome.com/blog/chrome-109-beta/&quot; rel=&quot;noopener&quot;&gt;Chrome 109&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The only new feature listed for Safari 16.3 is the addition of the Content-Security-Policy (CSP) &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/prefetch-src&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;prefetch-src&lt;/code&gt;&lt;/a&gt; directive. There are also a number of fixes in this beta.&lt;/p&gt;
&lt;p&gt;Chrome 109 supports &lt;a href=&quot;https://developer.mozilla.org/docs/Web/MathML&quot; rel=&quot;noopener&quot;&gt;MathML&lt;/a&gt; Core, a language for describing mathematical notation embeddable in HTML and SVG.&lt;/p&gt;
&lt;p&gt;New in Chrome on Android is &lt;a href=&quot;https://developer.chrome.com/blog/spc-on-android/&quot; rel=&quot;noopener&quot;&gt;Secure Payment Confirmation&lt;/a&gt; (SPC). This is a proposed web standard that allows customers to authenticate with a credit card issuer, bank, or other payment service provider using a platform authenticator—typically activated with a device&#39;s screen unlock feature such as a fingerprint sensor.&lt;/p&gt;
&lt;p&gt;Also new for Chrome on Android is the Origin Private File System (OPFS), part of the File System Access API on Android. This includes all of the File System Access API surface, minus the &lt;code&gt;show{OpenFile, SaveFile, Directory}Picker()&lt;/code&gt; methods and the Drag and Drop API integration.&lt;/p&gt;
&lt;p&gt;For CSS in Chrome we have the &lt;code&gt;lh&lt;/code&gt; length unit. This unit is equivalent to the computed value of the line-height property on the element on which it is used. Also, the &lt;code&gt;hyphenate-limit-chars&lt;/code&gt; property specifying the minimum number of characters in a hyphenated word.&lt;/p&gt;
&lt;p&gt;At the time of writing, and perhaps due to the holiday season, Firefox release notes haven&#39;t been updated.&lt;/p&gt;
&lt;h2 id=&quot;other-news&quot;&gt;Other news &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-12-2022/#other-news&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post marks the 12th edition of this &lt;a href=&quot;https://web.dev/tags/new-to-the-web/&quot;&gt;blog post series&lt;/a&gt;, bringing you a selection of interesting things landing in browsers each month in 2022. I&#39;ll be back in 2023 to continue sharing some of the interesting things landing on the web platform each month.&lt;/p&gt;
&lt;p&gt;Many of the features landing in browsers over this past year, and lots of those things mentioned as &amp;quot;CSS fixes,&amp;quot; were part of Interop 2022. For more information, read the Chrome team&#39;s &lt;a href=&quot;https://web.dev/interop-2022-wrapup/&quot;&gt;end-of-year report&lt;/a&gt; on this cross-browser initiative to improve some of the top interoperability pain points on the web platform.&lt;/p&gt;
&lt;p&gt;And finally, of interest to people who read this post, is this &lt;a href=&quot;https://developer.mozilla.org//plus/updates&quot; rel=&quot;noopener&quot;&gt;list of updates&lt;/a&gt; based on the MDN browser compatibility data, released by our friends over at MDN.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@worldsbetweenlines?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Patrick Hendry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Rachel Andrew</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Interop 2022: end of year update</title>
      <link href="https://web.dev/interop-2022-wrapup/"/>
      <updated>2022-12-19T00:00:00Z</updated>
      <id>https://web.dev/interop-2022-wrapup/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;We&#39;ve reached the end of another year, and it&#39;s time to look at the improvements made by browsers as we work together to improve the interoperability of the web platform. You can check out how things started in &lt;a href=&quot;https://web.dev/interop-2022/&quot;&gt;our post in March this year&lt;/a&gt;, as the initiative was launched.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Scores showing Chrome and Edge Dev on 71, Firefox Nightly on 74, Safari Technology Preview on 73.&quot; decoding=&quot;async&quot; height=&quot;372&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/s0O6F22XtjN6K9x9NLDs.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;The scores for experimental browsers in March 2022.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The overall scores at the end of the year show a great improvement across all engines.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Scores showing Chrome and Edge Dev on 90, Firefox Nightly on 89, Safari Technology Preview on 94.&quot; decoding=&quot;async&quot; height=&quot;391&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/bNJOIpIdpPbN4AFnrcQA.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;The scores for experimental browsers in December 2022.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In this post, learn about the progress made during 2022. In addition to these headline features, there were many smaller improvements made by all engines. Small issues that can cause inconsistencies between engines and trip you up during development, have been fixed. Seeing &lt;a href=&quot;https://web.dev/tags/newly-interoperable/&quot;&gt;big features available cross-browser&lt;/a&gt; is definitely exciting, but it&#39;s sometimes the small things that cause the most problems, and it&#39;s great to see how much has been improved.&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; &lt;a href=&quot;https://wpt.fyi/results/?view=subtest&amp;amp;q=%28label%3Ainterop-2021-aspect-ratio%20or%20label%3Ainterop-2021-flexbox%20or%20label%3Ainterop-2021-grid%20or%20label%3Ainterop-2021-position-sticky%20or%20label%3Ainterop-2021-transforms%20or%20label%3Ainterop-2022-cascade%20or%20label%3Ainterop-2022-color%20or%20label%3Ainterop-2022-contain%20or%20label%3Ainterop-2022-dialog%20or%20label%3Ainterop-2022-forms%20or%20label%3Ainterop-2022-scrolling%20or%20label%3Ainterop-2022-subgrid%20or%20label%3Ainterop-2022-text%20or%20label%3Ainterop-2022-viewport%20or%20label%3Ainterop-2022-webcompat%29%20exists%28status%3A%21pass%29%20seq%28status%3A%21missing%20status%3A%21missing%20status%3A%21missing%20status%3Apass%20status%3Apass%20status%3Apass%29&amp;amp;run_id=5694898400395264&amp;amp;run_id=5671385434161152&amp;amp;run_id=5747379813744640&amp;amp;run_id=4818947338141696&amp;amp;run_id=4882567984054272&amp;amp;run_id=5158468428759040&quot;&gt;Explore the tests&lt;/a&gt; that failed in at least one browser at the start of the year and now pass in all engines. Note that this link may be a little unreliable, try reloading if it&#39;s not working for you. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;cascade-layers&quot;&gt;Cascade layers &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#cascade-layers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Cascade_layers&quot; rel=&quot;noopener&quot;&gt;Cascade layers&lt;/a&gt; let you manage the cascade by grouping selectors into layers. It&#39;s the kind of feature that only becomes useful when it is supported everywhere. All major engines now support cascade layers, and the scores across all browsers reflect how interoperable the feature is, with just a few tests left to pass for Firefox.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 99, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        99
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 97, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        97
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 99, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        99
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@layer#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;the-dialog-element&quot;&gt;The dialog element &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#the-dialog-element&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/dialog&quot; rel=&quot;noopener&quot;&gt;The dialog element&lt;/a&gt; allows the creation of modal dialogs. This is a common pattern on the web, and using this element gives you usability and accessibility that you would otherwise have to develop and test when creating your own components. In the article &lt;a href=&quot;https://web.dev/building-a-dialog-component/&quot;&gt;Building a dialog component&lt;/a&gt;, Adam Argyle explains how to build on top of this element to build different types of dialogs.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 37, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        37
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 98, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        98
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        79
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/dialog#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;subgrid&quot;&gt;Subgrid &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#subgrid&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the beginning of 2022, the only browser supporting the &lt;code&gt;subgrid&lt;/code&gt; value for &lt;code&gt;grid-template-rows&lt;/code&gt; and &lt;code&gt;grid-template-columns&lt;/code&gt; was Firefox. During 2022 Safari has landed support, and the feature is under development in Chrome. It&#39;s going to miss the end of year deadline for interoperability, but it&#39;s on the way.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 71, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        71
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        16
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Grid_Layout/Subgrid#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;viewport-units&quot;&gt;Viewport units &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#viewport-units&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Viewport units are the only feature that has hit 100% of passing tests across all engines. This includes the concepts of the small and large viewport, that accounts for the changing viewport size on mobile as device UI elements appear and disappear. You can find out more about these units in the post &lt;a href=&quot;https://web.dev/viewport-units/&quot;&gt;the large, small, and dynamic viewport units&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 101, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        101
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;color-4&quot;&gt;Color 4 &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#color-4&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This collection of color work enables CSS to not only specify colors in higher definition gamuts (for example, display p3, rec2020), but also provides new color functions that each have unique utilities for working with color. New color spaces are &lt;code&gt;lch()&lt;/code&gt;, &lt;code&gt;oklch()&lt;/code&gt;, &lt;code&gt;lab()&lt;/code&gt;, &lt;code&gt;oklab()&lt;/code&gt;, &lt;code&gt;display-p3&lt;/code&gt;, &lt;code&gt;rec2020&lt;/code&gt;, &lt;code&gt;a98-rgb&lt;/code&gt;, &lt;code&gt;prophoto-rgb&lt;/code&gt;, &lt;code&gt;xyz&lt;/code&gt;, &lt;code&gt;xyz-d50&lt;/code&gt;, &lt;code&gt;xzy-d65&lt;/code&gt;: &lt;a href=&quot;https://codepen.io/argyleink/pen/RwyOyeq&quot; rel=&quot;noopener&quot;&gt;try these in Canary&lt;/a&gt; today with &lt;a href=&quot;chrome://flags/#enable-experimental-web-platform-features&quot; rel=&quot;noopener&quot;&gt;this flag enabled&lt;/a&gt;. These changes also apply to gradients, allowing authors to &lt;a href=&quot;https://codepen.io/argyleink/pen/OJObWEW&quot; rel=&quot;noopener&quot;&gt;specify which colorspace their gradients use&lt;/a&gt;. The same flag also enables &lt;a href=&quot;https://codepen.io/argyleink/pen/YzLMaor&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;color-mix()&lt;/code&gt;&lt;/a&gt; support, allowing you to mix two colors together in a space of your choice. The color-mix() function is also behind a flag in Safari and Firefox. More colors, better colors, better gradients, and better tools.&lt;/p&gt;
&lt;h2 id=&quot;interop-2023&quot;&gt;Interop 2023 &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/interop-2022-wrapup/#interop-2023&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hope you&#39;ll be happy to know that we aren&#39;t intending to stop at the end of 2022, and &lt;a href=&quot;https://web.dev/submit-your-proposals-for-interop-2023/&quot;&gt;Interop 2023&lt;/a&gt; is already well through the initial planning stage. In the New Year we&#39;ll be able to announce the features that have been selected, and look forward to another year of making it easier to develop for the web.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hero image by &lt;a href=&quot;https://unsplash.com/fr/@goian?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Ian Schneider&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Rachel Andrew</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Community highlight: Elisa Bandy</title>
      <link href="https://web.dev/community-highlight-elisa/"/>
      <updated>2022-12-13T00:00:00Z</updated>
      <id>https://web.dev/community-highlight-elisa/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;em&gt;This post highlights a community expert, as a part of
&lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility!&lt;/a&gt; Learn more about
&lt;a href=&quot;https://www.google.com/accessibility/initiatives-research/&quot; rel=&quot;noopener&quot;&gt;Google&#39;s accessibility initiatives and research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra White&lt;/strong&gt;: I&#39;m lucky to call you a colleague. How would you introduce yourself and your job here?&lt;/p&gt;
&lt;figure data-float=&quot;right&quot;&gt;
&lt;img alt=&quot;Elisa Bandy, Google technical writer.&quot; decoding=&quot;async&quot; height=&quot;426&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 300px) 300px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3wmp0figIYM6Y7IIvMhu.png?auto=format&amp;w=600 600w&quot; width=&quot;300&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Elisa Bandy&lt;/strong&gt;: My name is Elisa, and I write documentation for Google&#39;s
internal tooling and infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: That&#39;s such cool job. How many people do you work with?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Our broader team is about 40 people, and that includes technical
writers, instructional designers, and program managers. When I started, six
years ago, there were only four people on the team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: What were you up to before Google?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: During the week, I worked in video game development. And then on the
weekends, I worked in shoe repair.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Did you start working in web accessibility once you got to
Google?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Yes, but not until about a year and a half into it, on the side. I
work on accessibility engineering for Google&#39;s internal documentation. Before
this work, the docs were not designed with accessibility in mind. Any doc
feature that was accessible was a happy accident.&lt;/p&gt;
&lt;p&gt;There were huge issues, starting with color contrast being entirely
inappropriate for links. The tables were an absolute mess—if you zoomed in,
everything stayed the same size because it was defined in pixels instead of
&lt;code&gt;rem&lt;/code&gt;. I volunteered to fix all of those things. And then, I just kept fixing
more things. Here we are five years later, and I&#39;m still at it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You&#39;ve built yourself to be a person with accessibility
expertise and skills, and you&#39;ve got the resolve to fix the problems that need
to be fixed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Yeah, I guess we can say that [laughs]. As a disabled person myself,
I know how difficult it is to ask for accessibility considerations. So the fact
that we didn&#39;t have these accessibility considerations for my co-workers and my
colleagues really angered me. And no one else was fixing them. So I went in and
I fixed them.&lt;/p&gt;
&lt;p&gt;I don&#39;t think anyone should have to ask for accessibility. It should be built
in from the start.&lt;/p&gt;
&lt;h2 id=&quot;prioritize-your-accessibility-use-cases&quot;&gt;Prioritize your accessibility use cases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#prioritize-your-accessibility-use-cases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: When you think about web accessibility, there are so many
different layers to it, right? There are different, sometimes conflicting needs
for various disabilities. How do you prioritize what should be done?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: A lot of what I do is prioritization. For example, how important is
it that some specific use case be 100% totally accessible? I look at a lot of
data: what percentage of our population is disabled? How many people have a
specific accessibility issue?&lt;/p&gt;
&lt;p&gt;For example, there&#39;s a subset of users who use
&lt;a href=&quot;https://support.google.com/chromebook/answer/7031755&quot; rel=&quot;noopener&quot;&gt;ChromeVox&lt;/a&gt;, the built-in
screen reader for Chromebooks. If something is an issue in ChromeVox, I have to
take a look at how many people are using ChromeVox versus
&lt;a href=&quot;https://www.freedomscientific.com/products/software/jaws/&quot; rel=&quot;noopener&quot;&gt;Jaws&lt;/a&gt; versus
&lt;a href=&quot;https://www.nvaccess.org/about-nvda/&quot; rel=&quot;noopener&quot;&gt;NVDA&lt;/a&gt; versus
&lt;a href=&quot;https://support.apple.com/guide/voiceover/voiceover-keyboard-help-mchlp2683/10/mac/12.0&quot; rel=&quot;noopener&quot;&gt;VoiceOver&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Externally, not a lot of people use ChromeVox. Because we&#39;re Google, a lot of
people use Chromebooks as their primary work device, which means ChromeVox is
very important for internal documentation. Maybe a ChromeVox bug gets bumped up
a little higher than a VoiceOver bug or a NVDA bug.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  &lt;figure data-float=&quot;right&quot;&gt; &lt;a href=&quot;https://web.dev/learn/accessibility/design-ux/&quot; alt=&quot;Take the Design and user experience module.&quot;&gt; &lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;132&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 198px) 198px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=198 198w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=226 226w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=257 257w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=293 293w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=334 334w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=381 381w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/iJa4aaLGjRE7bN5A9CeX.png?auto=format&amp;w=396 396w&quot; width=&quot;198&quot; /&gt; &lt;/a&gt; &lt;/figure&gt;  Personas also offer a quick and inexpensive way to test and prioritize the features your users rely on in your development process. Take the Learn Accessibility module &lt;a href=&quot;https://web.dev/learn/accessibility/design-ux/&quot;&gt;Design and user experience&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Generally speaking, I try to fix things for the major screen readers first.
Coloration tends to be sort of hit or miss because there&#39;s a bunch of
extensions that circumnavigate coloration issues, especially for high contrast
modes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You mentioned data, which is incredibly important at Google (of
course). We always hear, &amp;quot;Back up your idea with data.&amp;quot; How do you collect data
for accessibility at Google?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: I rely a lot on data that&#39;s been collected by
&lt;a href=&quot;https://careers.google.com/stories/googles-disability-alliance/&quot; rel=&quot;noopener&quot;&gt;Google&#39;s Disability Alliance&lt;/a&gt;.
And I&#39;ll often cross-check with &lt;a href=&quot;https://webaim.org/&quot; rel=&quot;noopener&quot;&gt;WebAIM&lt;/a&gt;&#39;s surveys.&lt;/p&gt;
&lt;h2 id=&quot;culture-of-accessibility&quot;&gt;Culture of accessibility &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#culture-of-accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Tell me about the culture of accessibility at Google.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: It&#39;s grown very, very rapidly into something which has funding and
broad-reaching concern. And I have found that almost everyone wants to do the
right thing. Our colleagues want educational resources on how to do the right
thing, how to prioritize accessibility.&lt;/p&gt;
&lt;p&gt;Restructuring an app or a website or anything to be accessible after you&#39;ve
already implemented it incorrectly is &lt;em&gt;hard&lt;/em&gt;. So part of my job is getting our
engineers to think about incorporating accessibility into the initial designs,
before the products are built. People are very receptive to that, even
enthusiastic about it!&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  With component-driven development, you can establish accessibility into the base structure of your website or web app. Take the Learn Accessibility module &lt;a href=&quot;https://web.dev/learn/accessibility/patterns/&quot;&gt;Patterns, components, and design systems&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;I&#39;ve only ever had real resistance to incorporating accessibility once, and
even that was fairly easy to resolve.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Can you tell me more about that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: When I first joined accessibility engineering, it was only 20% of my
time. Some people didn&#39;t understand why we were focusing on accessibility.
Someone said, &amp;quot;Only 1% of the population is disabled.&amp;quot; I stood my
ground—we needed to do it because it was the right thing to do. And, it
was my time, I&#39;ll dedicate it how I see fit.&lt;/p&gt;
&lt;p&gt;Of course, it&#39;s hard to hear from anyone that disabled people don&#39;t matter,
that it&#39;s too small a group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Especially when you are a member of that population. Know your
audience!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: I never like to hear, &amp;quot;Oh, this is only 1%.&amp;quot; The &amp;quot;only&amp;quot; makes it
sound insignificant. But when you think about the global population, that&#39;s a
&lt;em&gt;lot&lt;/em&gt; of people. And that&#39;s a lot of people who work at Google. &lt;em&gt;And&lt;/em&gt; so many
disabilities are
&lt;a href=&quot;https://hbr.org/2019/06/why-people-hide-their-disabilities-at-work&quot; rel=&quot;noopener&quot;&gt;under-reported&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: We know that far more than 1% of the population are affected by
disabilities. &lt;a href=&quot;https://www.who.int/news-room/fact-sheets/detail/disability-and-health&quot; rel=&quot;noopener&quot;&gt;WHO reports&lt;/a&gt;
that over 1 billion people have a disability; and 2.2 billion people have
&lt;a href=&quot;https://www.who.int/news-room/fact-sheets/detail/blindness-and-visual-impairment&quot; rel=&quot;noopener&quot;&gt;some kind of vision impairment&lt;/a&gt;!
There&#39;s varying severity, of course, and some people with visual impairments
wouldn&#39;t consider themselves disabled. But these impairments do affect
interaction on the web.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Exactly.&lt;/p&gt;
&lt;h2 id=&quot;build-your-own-set-of-expertise&quot;&gt;Build your own set of expertise &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#build-your-own-set-of-expertise&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Is there any advice that you wish you had had before you started
working in accessibility?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: It&#39;s ok not to know every single thing. Accessibility is a huge,
wide expanse of space. I know that there&#39;s a lot of stuff that I don&#39;t know. I
have a very specific set of skills. It just so happens that I know where to
find information on what the accessibility best practices are.&lt;/p&gt;
&lt;p&gt;Even within my own specialty, screen readers and
&lt;a href=&quot;https://web.dev/learn/accessibility/color-contrast/&quot;&gt;color contrast&lt;/a&gt;, I&#39;m learning new things
every day. And I&#39;m deaf, but I&#39;m not an accessibility expert for Closed
Captions. I know what works for me, but I don&#39;t know what works for everyone
else. I&#39;d have to look up best practices if asked.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  Get a head start on best practices for &lt;a href=&quot;https://web.dev/learn/accessibility/video-audio/&quot;&gt;Video and audio&lt;/a&gt;. Closed Captions, transcripts, and other alternative media types support equal access to media.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: It&#39;s reasonable not to be the absolute expert of every kind of
accessibility. How would you help engineers learn accessibility patterns?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: I work closely with an engineer who&#39;s interested in accessibility.
I&#39;ll hand her a bug and show her how I would fix it. Then, I walk her through
the best practice. She may look at other docs and see they recommended one
approach, but it doesn&#39;t work for XYZ reasons.&lt;/p&gt;
&lt;p&gt;The thing about web accessibility is that there&#39;s not a lot of concrete code
examples, because no two people build the same feature in the same way. So you
might jury-rig solutions. Many people don&#39;t think about accessibility until
everything&#39;s been put together. What are you going to do at that point? Are you
going to tear it down and put it back together and rewrite all of your tests?
No, you&#39;re not. You&#39;re going to staple something on.&lt;/p&gt;
&lt;p&gt;That means you need to understand how a disabled user would expect the
application to function, then model your code so it performs that function. It
might not look like the perfect code samples or inclusive components, but
ultimately, as long as it performs the same function reliably, it&#39;s going to be
fine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: It sounds to me like you&#39;re saying it&#39;s more important to get a
positive result than to worry too much about how we get there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Yes. Because honestly the ends do justify the means of this case.
It&#39;s super important to understand how a screen reader user or any other
disabled user would expect this to work.&lt;/p&gt;
&lt;p&gt;There are a billion ARIA roles, and you cannot possibly know every single one.
Further, some don&#39;t work with all screen readers! So you need to know the needs
of your users to build for them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Are there common external resources that you rely on when
creating internal documentation or offering support to Google engineers?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: I do rely a lot on the &lt;a href=&quot;https://www.w3.org/&quot; rel=&quot;noopener&quot;&gt;W3C guidelines&lt;/a&gt;. They
are very good for getting an idea of what you need to do. WebAIM is another
extremely good resource that I find to be a little bit better with respect to
technical implementation. I also really like the Mozilla docs—nine times out
of ten, if I search for something, there&#39;s an answer in the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Accessibility&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I love &lt;a href=&quot;https://inclusive-components.design/&quot; rel=&quot;noopener&quot;&gt;inclusive-components.design&lt;/a&gt;,
which is great if you want a library of accessible components.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dequeuniversity.com/&quot; rel=&quot;noopener&quot;&gt;Deque University&lt;/a&gt; has a lot of best practices. I
use it for reference materials, when I&#39;m filing bugs or teaching someone how to
follow a specific pattern.&lt;/p&gt;
&lt;h2 id=&quot;experience-accessibility-tools-first-hand&quot;&gt;Experience accessibility tools first-hand &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#experience-accessibility-tools-first-hand&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: How does one go about learning how a user is affected? Since
your expertise is in supporting people who are colorblind and screen readers, let&#39;s start there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: For color vision deficiency and colorblindness, there are
simulators and &lt;a href=&quot;https://web.dev/blog/new-in-devtools-83/#vision-deficiencies&quot;&gt;emulators&lt;/a&gt;. You
really can&#39;t understand how someone else can see until you see it for yourself.
If I notice really bad saturation, as soon as I run it through the simulator, I
can confirm that it isn&#39;t discernible at all.&lt;/p&gt;
&lt;p&gt;To support screen reader users, there&#39;s no better way to understand it than to
actually use a screen reader. Read tutorials first, that&#39;s key. Some people get
frustrated when they just turn it on and try messing around with
it—that&#39;s a bad way to learn how to use them. You need more than 5 or 10
or 20 minutes. Use it for an hour at minimum to reveal some of the frustrations
users face who rely on this technology.&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;  Some external tutorials you may find useful:  &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://www.nuance.com/dragon/support/dragon-naturallyspeaking.html#getting-started&quot;&gt;Dragon getting started&lt;/a&gt; and &lt;a href=&quot;https://www.nuance.com/dragon/dragon-for-pc/how-to-videos.html&quot;&gt;demo videos&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://www.freedomscientific.com/training/jaws/additional-jaws-training-downloads/&quot;&gt;JAWS training&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://www.naturalreaders.com/software.html#FeaturesforWindows&quot;&gt;NaturalReader software demos&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://support.google.com/chromebook/answer/7031755&quot;&gt;ChromeVox help documentation&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;I&#39;m a firm believer that everyone is going to need accessibility technology at
some point in their life. For example, I recently hurt my wrist and couldn&#39;t
use my mouse, so I used a keyboard for multiple weeks. It was so frustrating.
These sorts of exercises can really help put you in the position of a disabled
person trying to navigate a world of able-bodied people.&lt;/p&gt;
&lt;h3 id=&quot;simulators,-while-useful,-are-not-equivalent-to-a-disability&quot;&gt;Simulators, while useful, are not equivalent to a disability &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#simulators,-while-useful,-are-not-equivalent-to-a-disability&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Obviously the experience that I have, or any developer would
have, using simulators is not the same as someone with a visual impairment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: You can always talk to someone who is disabled, to learn about their
experience. And when you&#39;re building that empathy, it&#39;s important to remember
that a person who frequently uses these tools is always going to be better at
it than you. Disabled people are always going to be better at navigating their
own spaces, because that&#39;s the body that that person lives with.&lt;/p&gt;
&lt;p&gt;My fear is that people who go through these empathy exercises, for lack of a
better term, think that they know precisely what people go through. They
suddenly think they&#39;re the expert on that experience. You&#39;re not the expert on
that experience. If you&#39;re able-bodied, you&#39;re fundamentally not the expert on
screen readers. I&#39;m not an expert on being colorblind, even though I work in
this space. I&#39;m not an expert on screen readers.&lt;/p&gt;
&lt;p&gt;I am an expert in my experience of being hard of hearing. I am an expert on
needing a hearing aid and navigating my own experiences every day. But that
doesn&#39;t mean I&#39;m an expert in other people&#39;s experience with deafness&lt;/p&gt;
&lt;p&gt;The worst thing you can do in accessibility engineering is have an ego. No
matter what you do, you&#39;re going to mess something up. That&#39;s not something to
get discouraged about because no two people have the same disability needs. No
two people have the same viewpoint on accessibility and disabilities. You
cannot do everything 100%—but that doesn&#39;t mean you shouldn&#39;t try. You
won&#39;t ever be perfect, but strive for it anyway.&lt;/p&gt;
&lt;p&gt;You may get critical feedback, someone may say, &amp;quot;Hey, your product is not
accessible!&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Simulators support a different learning style, demonstrating
your product while facing some of the problems that disabled people may
experience. But, that&#39;s not the same as experiencing your product with the
accessibility tools they use every day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Do I get mildly annoyed when people turn the sound off and read
captions and then suddenly realize, oh, these automatically generated
captions are terrible? Yeah. That&#39;s not how I experience captions. Some
disabled people see a person emulate their experience and complain
about the tools, without actively needing those tools. That&#39;s frustrating,
I really get that.&lt;/p&gt;
&lt;p&gt;But I also don&#39;t want to be the person who has to sit there and describe my
experience as a deaf person over and over and over and over and over again.
Every single time. If we want able-bodied people to understand our experiences,
we&#39;re going to have to put up with their reaction to the experiences.&lt;/p&gt;
&lt;p&gt;That said, the &amp;quot;experiences&amp;quot; like blind restaurant dining and wine tasting,
those make me mad. That&#39;s like cosplaying a disability. But in the interests of
trying to understand how your users use a feature or how readers read the page?
That&#39;s fine. In fact, that&#39;s the minimum. Put yourself in their shoes for an
hour and figure out how these things actually work. It really does matter.&lt;/p&gt;
&lt;p&gt;Figure out how people navigate on your site. You may wonder, &amp;quot;Why can&#39;t I just
put a banner warning at the top that all the links open in a new tab?&amp;quot; Well,
because someone might not be reading the page starting with the banner. Build
your design with disabled people in mind.&lt;/p&gt;
&lt;h2 id=&quot;do-one-thing-stop-building-infinite-scroll&quot;&gt;Do one thing: stop building infinite scroll &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-elisa/#do-one-thing-stop-building-infinite-scroll&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Is there one thing you wish that engineers would just start
doing to make their sites more accessible?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elisa&lt;/strong&gt;: Infinite scroll is a blight and no one should ever use it. I can&#39;t
find things, I need to be able to find things! And, it&#39;s so bad for performance.&lt;/p&gt;
&lt;p&gt;Also, moving things around visually and within the DOM is really annoying. The
tab order matters, especially for keyboard users.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  ​​Take the Learn Accessibility module on &lt;a href=&quot;https://web.dev/learn/accessibility/focus/&quot;&gt;Keyboard focus&lt;/a&gt; to discover how to ensure all users can navigate your content.  &lt;/div&gt;&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;Learn more about &lt;a href=&quot;https://www.google.com/accessibility/initiatives-research/&quot; rel=&quot;noopener&quot;&gt;Google&#39;s accessibility initiatives and research&lt;/a&gt;.
In addition to the web development resources at
&lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility&lt;/a&gt;, Google has created an accessible
documentation course:
&lt;a href=&quot;https://developers.google.com/tech-writing/accessibility&quot; rel=&quot;noopener&quot;&gt;Tech Writing for Accessibility&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Follow Google&#39;s Accessibility team on Twitter at
&lt;a href=&quot;https://twitter.com/googleaccess&quot; rel=&quot;noopener&quot;&gt;@GoogleAccess&lt;/a&gt; and the Chrome team at
&lt;a href=&quot;https://twitter.com/ChromiumDev&quot; rel=&quot;noopener&quot;&gt;@ChromiumDev&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Optimize Interaction to Next Paint</title>
      <link href="https://web.dev/optimize-inp/"/>
      <updated>2022-12-08T00:00:00Z</updated>
      <id>https://web.dev/optimize-inp/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; is an experimental metric that assesses a page&#39;s overall responsiveness to user interactions by observing the latency of all &lt;a href=&quot;https://web.dev/better-responsiveness-metric/#interaction-types&quot;&gt;click, tap, and keyboard interactions&lt;/a&gt; that occur throughout the lifespan of a user&#39;s visit to a page. The final INP value is the longest interaction observed, ignoring outliers.&lt;/p&gt;
&lt;p&gt;To provide a good user experience, sites should strive to have an Interaction to Next Paint of &lt;strong&gt;200 milliseconds or less&lt;/strong&gt;. To ensure you&#39;re hitting this target for most of your users, a good threshold to measure is the &lt;strong&gt;75th percentile&lt;/strong&gt; of page loads, segmented across mobile and desktop devices.&lt;/p&gt;
&lt;style&gt;
  .inp-mobile {
    display: inline;
  }

  .inp-desktop {
    display: none;
  }

  @media screen and (min-width: 640px) {
    .inp-mobile {
      display: none;
    }

    .inp-desktop {
      display: inline;
    }
  }
&lt;/style&gt;
&lt;figure&gt;
  &lt;svg title=&quot;A diagram of the INP thresholds. An INP at or below 200 milliseconds is considered good. Between 200 and 500 milliseconds suggests a page&#39;s responsiveness needs improvement. Anything over 500 milliseconds means that a page&#39;s responsiveness is poor.&quot; class=&quot;inp-mobile&quot; version=&quot;1.1&quot; id=&quot;Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; x=&quot;0&quot; y=&quot;0&quot; viewBox=&quot;0 0 296.6 220.2&quot; style=&quot;enable-background:new 0 0 296.6 220.2&quot; xml:space=&quot;preserve&quot;&gt;&lt;style&gt;.st0{fill:#2979FF} .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#0CCE6B} .st2{fill:#191919} .st3{fill-rule:evenodd;clip-rule:evenodd;fill:#FFA400} .st4{fill-rule:evenodd;clip-rule:evenodd;fill:#FF4E42} @media screen and (prefers-color-scheme: light){.st2{fill:#191919}} [data-user-theme=light] .st2 {fill:#191919} @media screen and (prefers-color-scheme: dark){.st2{fill:#fff}} [data-user-theme=dark] .st2{fill:#fff}&lt;/style&gt;&lt;path class=&quot;st0&quot; d=&quot;M83.3 63V0h11.9v63H83.3zm26.3 0V0h13.8l25.3 42.2h.7l-.7-12.1V0h11.8v63H148l-26.8-44.6h-.7l.7 12.1V63h-11.6zm65.4 0V0h22.2c4.1 0 7.7.8 10.9 2.5s5.8 4 7.7 7 2.9 6.4 2.9 10.4c0 3.9-1 7.4-2.9 10.4s-4.5 5.4-7.7 7c-3.2 1.7-6.9 2.5-10.9 2.5h-15.6V28.6h15.9c2.1 0 3.8-.4 5.2-1.2s2.5-1.9 3.2-3.2c.7-1.3 1.1-2.8 1.1-4.3s-.4-2.9-1.1-4.2c-.7-1.3-1.8-2.3-3.2-3.2s-3.1-1.2-5.2-1.2h-10.7V63H175z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st1&quot; d=&quot;M0 137.1h96v38.4H0v-38.4z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M34 161c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-.9-.4-.4-.7-.9-1-1.4-.2-.6-.3-1.1-.3-1.8 0-.6.1-1.2.3-1.8.2-.6.6-1 1-1.4.4-.4.9-.7 1.4-.9.5-.2 1.1-.3 1.8-.3s1.3.1 1.8.3c.6.2 1 .6 1.4 1l-.9.9c-.2-.2-.4-.4-.6-.5-.2-.1-.5-.3-.8-.3-.3-.1-.6-.1-.9-.1-.4 0-.8.1-1.2.2-.4.1-.7.4-1 .6-.3.3-.5.6-.7 1-.2.4-.2.8-.2 1.3s.1.9.2 1.3c.2.4.4.7.7 1 .3.3.6.5 1 .7.4.1.8.2 1.2.2.4 0 .8-.1 1.1-.2.3-.1.6-.3.9-.5.3-.2.5-.5.6-.8.2-.3.3-.6.3-1H34v-1.2h4.2v.7c0 .6-.1 1.2-.3 1.7-.2.5-.5.9-.9 1.3s-.8.6-1.3.8c-.5.3-1.1.4-1.7.4zm9.5 0c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-.9-.9-1.4-.2-.5-.3-1.1-.3-1.8 0-.6.1-1.2.3-1.8.2-.5.5-1 .9-1.4.4-.4.9-.7 1.4-1 .5-.2 1.1-.3 1.8-.3.6 0 1.2.1 1.8.3.5.2 1 .6 1.4 1 .4.4.7.9.9 1.4.2.5.3 1.1.3 1.8 0 .6-.1 1.2-.3 1.8-.2.5-.5 1-.9 1.4-.4.4-.9.7-1.4 1-.5.2-1.1.3-1.8.3zm0-1.2c.6 0 1.1-.1 1.6-.4.5-.3.8-.7 1.1-1.1.3-.5.4-1.1.4-1.7 0-.6-.1-1.2-.4-1.7-.3-.5-.7-.9-1.1-1.1-.5-.3-1-.4-1.6-.4-.6 0-1.1.1-1.6.4-.5.3-.8.7-1.1 1.1-.3.5-.4 1-.4 1.7 0 .6.1 1.2.4 1.7.3.5.7.9 1.1 1.1.5.3 1 .4 1.6.4zm9.9 1.2c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-.9-.9-1.4-.2-.5-.3-1.1-.3-1.8 0-.6.1-1.2.3-1.8.2-.5.5-1 .9-1.4.4-.4.9-.7 1.4-1 .5-.2 1.1-.3 1.8-.3.6 0 1.2.1 1.8.3.5.2 1 .6 1.4 1 .4.4.7.9.9 1.4.2.5.3 1.1.3 1.8 0 .6-.1 1.2-.3 1.8-.2.5-.5 1-.9 1.4-.4.4-.9.7-1.4 1-.6.2-1.2.3-1.8.3zm0-1.2c.6 0 1.1-.1 1.6-.4.5-.3.8-.7 1.1-1.1.3-.5.4-1.1.4-1.7 0-.6-.1-1.2-.4-1.7-.3-.5-.7-.9-1.1-1.1-.5-.3-1-.4-1.6-.4-.6 0-1.1.1-1.6.4-.5.3-.8.7-1.1 1.1-.3.5-.4 1-.4 1.7 0 .6.1 1.2.4 1.7.3.5.7.9 1.1 1.1.5.3 1 .4 1.6.4zm6 1.1v-8.6h2.8c.9 0 1.7.2 2.3.5.7.4 1.2.9 1.5 1.5.4.6.5 1.4.5 2.2 0 .8-.2 1.6-.5 2.2-.4.6-.9 1.2-1.5 1.5-.6.4-1.4.5-2.3.5h-2.8zm1.3-1.3h1.4c.6 0 1.2-.1 1.7-.4.5-.3.8-.6 1.1-1 .2-.5.4-1 .4-1.6 0-.6-.1-1.2-.4-1.6-.2-.5-.6-.8-1.1-1-.5-.3-1-.4-1.7-.4h-1.4v6z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st3&quot; d=&quot;M96 137.1h105.6v38.4H96v-38.4z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M130.8 153.9v-8.6h1.6l3.9 6.3h.1l-.1-1.7v-4.7h1.3v8.6h-1.4l-4.1-6.6h-.1l.1 1.7v5h-1.3zm8.7 0v-8.6h5.2v1.2h-3.9v6.1h3.9v1.2h-5.2zm.7-3.7V149h4.1v1.2h-4.1zm6.2 3.7v-8.6h5.2v1.2h-3.9v6.1h3.9v1.2h-5.2zm.7-3.7V149h4.1v1.2h-4.1zm6.1 3.7v-8.6h2.8c.9 0 1.7.2 2.3.5.7.4 1.2.9 1.5 1.5.4.6.5 1.4.5 2.2s-.2 1.6-.5 2.2c-.4.6-.9 1.2-1.5 1.5-.6.4-1.4.5-2.3.5h-2.8zm1.3-1.3h1.4c.6 0 1.2-.1 1.7-.4.5-.2.8-.6 1.1-1 .2-.5.4-1 .4-1.6 0-.6-.1-1.2-.4-1.6-.2-.5-.6-.8-1.1-1-.5-.2-1-.4-1.7-.4h-1.4v6zm9.9 1.4c-.5 0-.9-.1-1.3-.3-.4-.2-.8-.4-1.1-.8-.3-.4-.5-.8-.7-1.3l1.2-.5c.1.5.3.9.7 1.2.3.3.7.5 1.2.5.3 0 .5 0 .8-.1.2-.1.4-.2.6-.4s.2-.4.2-.7c0-.3-.1-.5-.2-.7-.1-.2-.3-.3-.6-.5s-.6-.3-1-.5l-.5-.2c-.2-.1-.5-.2-.7-.3-.2-.1-.5-.3-.7-.5-.2-.2-.4-.4-.5-.7-.1-.3-.2-.6-.2-.9 0-.4.1-.8.3-1.2.2-.4.5-.6.9-.8.4-.2.9-.3 1.4-.3.6 0 1 .1 1.4.3.4.2.7.4.9.7.2.3.4.5.4.8l-1.2.5c0-.2-.1-.3-.2-.5s-.3-.3-.5-.4c-.2-.1-.4-.2-.8-.2-.2 0-.5.1-.7.2-.2.1-.4.2-.5.4-.1.2-.2.3-.2.6s.1.6.4.8c.3.2.6.4 1.1.5l.6.2c.3.1.6.2.8.3.3.1.5.3.7.5.2.2.4.4.5.7.1.3.2.6.2 1s-.1.8-.3 1.2c-.2.3-.4.6-.7.8-.3.2-.6.3-.9.4s-.5.2-.8.2zM107 167.9v-8.6h1.3v8.6H107zm3.2 0v-8.6h1.8l2.5 6.5h.1l2.5-6.5h1.8v8.6h-1.3V163l.1-1.5h-.1l-2.5 6.4h-1l-2.5-6.4h-.1l.1 1.5v4.9h-1.4zm10.6 0v-8.6h3c.5 0 1 .1 1.4.3.4.2.8.5 1 .9.3.4.4.9.4 1.4 0 .5-.1 1-.4 1.4-.2.4-.6.7-1 .9-.4.2-.9.3-1.4.3h-2.2v-1.2h2.3c.3 0 .6-.1.8-.2.2-.1.4-.3.5-.5.1-.2.2-.4.2-.7 0-.2-.1-.4-.2-.7-.1-.2-.3-.4-.5-.5-.2-.1-.5-.2-.8-.2h-1.7v7.3h-1.4zm7.2 0v-8.6h3c.5 0 1 .1 1.4.3.4.2.7.5 1 .9.2.4.4.8.4 1.4 0 .3-.1.7-.2 1s-.3.6-.6.8c-.3.2-.6.4-1 .6-.4.1-.8.2-1.2.2h-2.1v-1.2h2.3c.3 0 .5-.1.7-.2.2-.1.4-.3.5-.5.1-.2.2-.5.2-.7 0-.2-.1-.5-.2-.7-.1-.2-.3-.4-.5-.5-.2-.1-.5-.2-.8-.2h-1.7v7.4H128zm2-4h1.5l2.7 3.9v.1h-1.5l-2.7-4zm9.3 4.1c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-.9-.9-1.4-.2-.5-.3-1.1-.3-1.8s.1-1.2.3-1.8c.2-.5.5-1 .9-1.4.4-.4.9-.7 1.4-1 .5-.2 1.1-.3 1.8-.3.6 0 1.2.1 1.8.3.5.2 1 .6 1.4 1 .4.4.7.9.9 1.4.2.5.3 1.1.3 1.8s-.1 1.2-.3 1.8c-.2.5-.5 1-.9 1.4-.4.4-.9.7-1.4 1-.6.2-1.2.3-1.8.3zm0-1.2c.6 0 1.1-.1 1.6-.4.5-.3.8-.7 1.1-1.1.3-.5.4-1.1.4-1.7 0-.6-.1-1.2-.4-1.7-.3-.5-.7-.9-1.1-1.1-.5-.3-1-.4-1.6-.4-.6 0-1.1.1-1.6.4-.5.3-.8.7-1.1 1.1-.3.5-.4 1-.4 1.7 0 .6.1 1.2.4 1.7.3.5.7.9 1.1 1.1.5.3 1 .4 1.6.4zm7.9 1.1-3-8.6h1.4l1.9 5.7.3 1h.1l.3-1 2-5.7h1.4l-3.1 8.6h-1.3zm5.6 0v-8.6h5.2v1.2h-3.9v6.1h3.9v1.2h-5.2zm.7-3.7V163h4.1v1.2h-4.1zm6.2 3.7v-8.6h1.8l2.5 6.5h.1l2.5-6.5h1.8v8.6H167V163l.1-1.5h-.1l-2.5 6.4h-1l-2.5-6.4h-.1l.1 1.5v4.9h-1.3zm10.6 0v-8.6h5.2v1.2h-3.9v6.1h3.9v1.2h-5.2zm.7-3.7V163h4.1v1.2H171zm6.1 3.7v-8.6h1.6l3.9 6.3h.1l-.1-1.7v-4.7h1.3v8.6h-1.4l-4.1-6.6h-.1l.1 1.7v5h-1.3zm10.5 0V160h1.3v7.9h-1.3zm-2.4-7.4v-1.2h6.1v1.2h-6.1z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st4&quot; d=&quot;M200.6 137.1h96v38.4h-96v-38.4z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M232.5 160.9v-8.6h3c.5 0 1 .1 1.4.3.4.2.8.5 1 .9.3.4.4.9.4 1.4 0 .5-.1 1-.4 1.4-.2.4-.6.7-1 .9-.4.2-.9.3-1.4.3h-2.2v-1.2h2.3c.3 0 .6-.1.8-.2.2-.1.4-.3.5-.5.1-.2.2-.4.2-.7 0-.2-.1-.4-.2-.7-.1-.2-.3-.4-.5-.5-.2-.1-.5-.2-.8-.2h-1.7v7.3h-1.4zm11 .1c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-.9-.9-1.4-.2-.5-.3-1.1-.3-1.8s.1-1.2.3-1.8c.2-.5.5-1 .9-1.4.4-.4.9-.7 1.4-1 .5-.2 1.1-.3 1.8-.3.6 0 1.2.1 1.8.3.5.2 1 .6 1.4 1 .4.4.7.9.9 1.4.2.5.3 1.1.3 1.8s-.1 1.2-.3 1.8c-.2.5-.5 1-.9 1.4-.4.4-.9.7-1.4 1-.5.2-1.1.3-1.8.3zm0-1.2c.6 0 1.1-.1 1.6-.4.5-.3.8-.7 1.1-1.1.3-.5.4-1.1.4-1.7 0-.6-.1-1.2-.4-1.7-.3-.5-.7-.9-1.1-1.1-.5-.3-1-.4-1.6-.4-.6 0-1.1.1-1.6.4-.5.3-.8.7-1.1 1.1-.3.5-.4 1-.4 1.7 0 .6.1 1.2.4 1.7.3.5.7.9 1.1 1.1.6.3 1.1.4 1.6.4zm9.9 1.2c-.6 0-1.2-.1-1.8-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-.9-.9-1.4-.2-.5-.3-1.1-.3-1.8s.1-1.2.3-1.8c.2-.5.5-1 .9-1.4.4-.4.9-.7 1.4-1 .5-.2 1.1-.3 1.8-.3.6 0 1.2.1 1.8.3.5.2 1 .6 1.4 1 .4.4.7.9.9 1.4.2.5.3 1.1.3 1.8s-.1 1.2-.3 1.8c-.2.5-.5 1-.9 1.4-.4.4-.9.7-1.4 1-.6.2-1.1.3-1.8.3zm0-1.2c.6 0 1.1-.1 1.6-.4.5-.3.8-.7 1.1-1.1.3-.5.4-1.1.4-1.7 0-.6-.1-1.2-.4-1.7-.3-.5-.7-.9-1.1-1.1-.5-.3-1-.4-1.6-.4-.6 0-1.1.1-1.6.4-.5.3-.8.7-1.1 1.1-.3.5-.4 1-.4 1.7 0 .6.1 1.2.4 1.7.3.5.7.9 1.1 1.1.5.3 1 .4 1.6.4zm6 1.1v-8.6h3c.5 0 1 .1 1.4.3.4.2.7.5 1 .9.2.4.4.8.4 1.4 0 .3-.1.7-.2 1s-.3.6-.6.8c-.3.2-.6.4-1 .6-.4.1-.8.2-1.2.2h-2.1v-1.2h2.3c.3 0 .5-.1.7-.2.2-.1.4-.3.5-.5.1-.2.2-.5.2-.7 0-.2-.1-.5-.2-.7-.1-.2-.3-.4-.5-.5-.2-.1-.5-.2-.8-.2h-1.7v7.4h-1.2zm2-4h1.5l2.7 3.9v.1H264l-2.6-4zM178.1 219.9c-.5 0-1-.1-1.5-.3-.5-.2-1-.5-1.4-1-.4-.4-.7-1-.8-1.7l1.5-.6c.1.6.4 1 .8 1.4.4.4.9.5 1.4.5.6 0 1.1-.2 1.5-.6.4-.4.6-.9.6-1.5s-.2-1.1-.6-1.5c-.4-.4-.9-.6-1.5-.6-.4 0-.7.1-1 .2-.3.1-.5.4-.7.6l-1.7-.8.7-5.5h5.9v1.6h-4.5l-.4 2.9h.1c.2-.2.5-.3.8-.5.3-.1.7-.2 1.2-.2.6 0 1.2.2 1.7.5s1 .7 1.3 1.3c.3.5.5 1.2.5 1.9s-.2 1.3-.5 1.9c-.3.6-.8 1-1.3 1.3-.7.5-1.4.7-2.1.7zm9.9 0c-.7 0-1.3-.1-1.9-.4-.5-.3-1-.7-1.4-1.2-.4-.5-.7-1.1-.9-1.8-.2-.7-.3-1.4-.3-2.2 0-.8.1-1.6.3-2.2.2-.7.5-1.3.9-1.8s.9-.9 1.4-1.2c.6-.3 1.2-.5 1.9-.5s1.3.2 1.9.5c.6.3 1 .7 1.4 1.2.4.5.7 1.1.9 1.8.2.7.3 1.4.3 2.2 0 .8-.1 1.6-.3 2.2-.2.7-.5 1.3-.9 1.8s-.9.9-1.4 1.2c-.6.2-1.2.4-1.9.4zm.1-1.7c.6 0 1-.2 1.5-.5.4-.4.7-.9 1-1.5.2-.6.3-1.3.3-2.1s-.1-1.5-.3-2.1c-.2-.6-.5-1.1-1-1.5-.4-.4-.9-.5-1.5-.5s-1.1.2-1.5.5c-.4.4-.7.8-.9 1.5-.2.6-.3 1.3-.3 2.1s.1 1.5.3 2.1c.2.6.5 1.1.9 1.5.4.3.9.5 1.5.5zm10.5 1.7c-.7 0-1.3-.1-1.9-.4-.5-.3-1-.7-1.4-1.2-.4-.5-.7-1.1-.9-1.8-.2-.7-.3-1.4-.3-2.2 0-.8.1-1.6.3-2.2.2-.7.5-1.3.9-1.8s.9-.9 1.4-1.2c.6-.3 1.2-.5 1.9-.5s1.3.2 1.9.5c.6.3 1 .7 1.4 1.2.4.5.7 1.1.9 1.8.2.7.3 1.4.3 2.2 0 .8-.1 1.6-.3 2.2-.2.7-.5 1.3-.9 1.8s-.9.9-1.4 1.2c-.6.2-1.2.4-1.9.4zm0-1.7c.6 0 1-.2 1.5-.5.4-.4.7-.9 1-1.5.2-.6.3-1.3.3-2.1s-.1-1.5-.3-2.1c-.2-.6-.5-1.1-1-1.5-.4-.4-.9-.5-1.5-.5s-1.1.2-1.5.5c-.4.4-.7.8-.9 1.5-.2.6-.3 1.3-.3 2.1s.1 1.5.3 2.1c.2.6.5 1.1.9 1.5.4.3.9.5 1.5.5zm10 1.4v-8.2h1.6v1.1h.1c.2-.3.4-.5.6-.7.3-.2.6-.4.9-.5.3-.1.7-.2 1-.2.6 0 1.1.1 1.5.4.4.3.7.7.9 1.1.3-.4.6-.8 1.1-1.1.5-.3 1-.5 1.7-.5 1 0 1.7.3 2.1.9.5.6.7 1.4.7 2.3v5.2h-1.7v-4.9c0-.7-.1-1.1-.4-1.4-.3-.3-.7-.5-1.2-.5-.4 0-.7.1-1 .3-.3.2-.5.5-.7.9-.2.4-.2.8-.2 1.2v4.4h-1.7v-4.9c0-.7-.1-1.1-.4-1.4-.3-.3-.7-.5-1.2-.5-.4 0-.7.1-1 .3-.3.2-.5.5-.7.9-.2.4-.2.8-.2 1.2v4.4h-1.8zm17.2.3c-.6 0-1.2-.1-1.7-.3-.5-.2-.9-.5-1.2-.8-.3-.3-.5-.7-.7-1.1l1.5-.7c.2.4.5.8.8 1 .4.2.8.3 1.2.3.4 0 .8-.1 1.1-.2.3-.2.5-.4.5-.8 0-.2-.1-.4-.2-.6-.1-.1-.3-.3-.6-.4-.2-.1-.5-.2-.8-.2l-1-.2c-.4-.1-.8-.3-1.1-.5-.3-.2-.6-.5-.8-.8-.2-.3-.3-.7-.3-1.1 0-.5.1-.9.4-1.3.3-.4.7-.6 1.1-.8.5-.2 1-.3 1.6-.3.5 0 1 .1 1.4.2.4.1.8.3 1.1.6.3.3.6.6.8 1l-1.5.7c-.2-.4-.4-.6-.7-.8-.3-.1-.6-.2-1-.2s-.7.1-1 .2c-.3.2-.4.4-.4.6 0 .3.1.5.4.7.2.2.5.3.9.4l1.2.3c.8.2 1.4.5 1.8.9.4.4.6.9.6 1.5 0 .5-.2 1-.5 1.4-.3.4-.7.7-1.2.9-.6.2-1.1.4-1.7.4zM69 220v-1.6s.2-.1.4-.4c.2-.2.5-.5.8-.9l1.1-1.1 1-1c.3-.3.5-.6.7-.8.3-.3.5-.6.7-.8.2-.2.3-.5.4-.7.1-.2.1-.5.1-.8 0-.3-.1-.5-.2-.8-.1-.3-.3-.4-.6-.6-.3-.1-.6-.2-1-.2s-.7.1-1 .2c-.3.1-.5.3-.6.6-.1.2-.3.4-.3.7l-1.5-.6c.1-.3.2-.5.4-.8.2-.3.4-.5.7-.8.3-.3.6-.5 1-.6.4-.2.9-.3 1.4-.2.7 0 1.3.2 1.9.5.5.3.9.7 1.2 1.2.3.5.4 1 .4 1.6 0 .5-.1.9-.2 1.3-.2.4-.4.8-.7 1.2-.3.4-.5.7-.8 1l-.5.5c-.2.2-.4.5-.7.7l-.7.7-.6.6-.4.4h4.8v1.6H69zm13.2.2c-.7 0-1.3-.1-1.9-.4-.5-.3-1-.7-1.4-1.2-.4-.5-.7-1.1-.9-1.8-.2-.7-.3-1.4-.3-2.2 0-.8.1-1.6.3-2.2.2-.7.5-1.3.9-1.8s.9-.9 1.4-1.2c.6-.3 1.2-.5 1.9-.5s1.3.2 1.9.5c.6.3 1 .7 1.4 1.2.4.5.7 1.1.9 1.8.2.7.3 1.4.3 2.2 0 .8-.1 1.6-.3 2.2-.2.7-.5 1.3-.9 1.8s-.9.9-1.4 1.2c-.6.3-1.2.4-1.9.4zm0-1.6c.6 0 1-.2 1.5-.5.4-.4.7-.9 1-1.5.2-.6.3-1.3.3-2.1s-.1-1.5-.3-2.1c-.2-.6-.5-1.1-1-1.5-.4-.4-.9-.5-1.5-.5s-1.1.2-1.5.5c-.4.4-.7.8-.9 1.5-.2.6-.3 1.3-.3 2.1s.1 1.5.3 2.1c.2.6.5 1.1.9 1.5.4.3.9.5 1.5.5zm10.5 1.6c-.7 0-1.3-.1-1.9-.4-.5-.3-1-.7-1.4-1.2-.4-.5-.7-1.1-.9-1.8-.2-.7-.3-1.4-.3-2.2 0-.8.1-1.6.3-2.2.2-.7.5-1.3.9-1.8s.9-.9 1.4-1.2c.6-.3 1.2-.5 1.9-.5s1.3.2 1.9.5c.6.3 1 .7 1.4 1.2.4.5.7 1.1.9 1.8.2.7.3 1.4.3 2.2 0 .8-.1 1.6-.3 2.2-.2.7-.5 1.3-.9 1.8s-.9.9-1.4 1.2c-.6.3-1.2.4-1.9.4zm0-1.6c.6 0 1-.2 1.5-.5.4-.4.7-.9 1-1.5.2-.6.3-1.3.3-2.1s-.1-1.5-.3-2.1c-.2-.6-.5-1.1-1-1.5-.4-.4-.9-.5-1.5-.5s-1.1.2-1.5.5c-.4.4-.7.8-.9 1.5-.2.6-.3 1.3-.3 2.1s.1 1.5.3 2.1c.2.6.5 1.1.9 1.5.5.3 1 .5 1.5.5zm10 1.4v-8.2h1.6v1.1h.1c.2-.3.4-.5.6-.7.3-.2.6-.4.9-.5.3-.1.7-.2 1-.2.6 0 1.1.1 1.5.4.4.3.7.7.9 1.1.3-.4.6-.8 1.1-1.1.5-.3 1-.5 1.7-.5 1 0 1.7.3 2.1.9.5.6.7 1.4.7 2.3v5.2h-1.7v-4.9c0-.7-.1-1.1-.4-1.4-.3-.3-.7-.5-1.2-.5-.4 0-.7.1-1 .3-.3.2-.5.5-.7.9-.2.4-.2.8-.2 1.2v4.4H108v-4.9c0-.7-.1-1.1-.4-1.4-.3-.3-.7-.5-1.2-.5-.4 0-.7.1-1 .3-.3.2-.5.5-.7.9-.2.4-.2.8-.2 1.2v4.4h-1.8zm17.2.2c-.6 0-1.2-.1-1.7-.3-.5-.2-.9-.5-1.2-.8-.3-.3-.5-.7-.7-1.1l1.5-.7c.2.4.5.8.8 1 .4.2.8.3 1.2.3.4 0 .8-.1 1.1-.2.3-.2.5-.4.5-.8 0-.2-.1-.4-.2-.6-.1-.1-.3-.3-.6-.4-.2-.1-.5-.2-.8-.2l-1-.2c-.4-.1-.8-.3-1.1-.5-.3-.2-.6-.5-.8-.8-.2-.3-.3-.7-.3-1.1 0-.5.1-.9.4-1.3.3-.4.7-.6 1.1-.8.5-.2 1-.3 1.6-.3.5 0 1 .1 1.4.2.4.1.8.3 1.1.6.3.3.6.6.8 1l-1.5.7c-.2-.4-.4-.6-.7-.8-.3-.1-.6-.2-1-.2s-.7.1-1 .2c-.3.2-.4.4-.4.6 0 .3.1.5.4.7.2.2.5.3.9.4l1.2.3c.8.2 1.4.5 1.8.9.4.4.6.9.6 1.5 0 .5-.2 1-.5 1.4-.3.4-.7.7-1.2.9-.5.3-1.1.4-1.7.4zM42.4 96.3V82h1.7v14.3h-1.7zm4.6 0V86.1h1.6v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V90c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7H47zm10-10.2h6v1.5h-6v-1.5zm1.8 7.5V83.3h1.7v10c0 .5.1.9.3 1.2s.6.4 1.1.4c.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.5-.6-.7-1.3-.7-2.2zm10.3 3c-1 0-1.9-.2-2.6-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.6-1.7-.6-2.8 0-1 .2-1.9.6-2.7s1-1.5 1.7-2 1.6-.8 2.6-.8 1.9.2 2.6.7c.7.4 1.3 1.1 1.7 1.8.4.8.6 1.7.6 2.7v.5H65V90h7c0-.3-.1-.6-.2-.9-.1-.3-.3-.6-.5-.9-.2-.3-.6-.5-.9-.7-.4-.2-.8-.3-1.4-.3-.7 0-1.2.2-1.7.5s-.8.8-1.1 1.4c-.3.6-.4 1.2-.4 2 0 .9.2 1.6.5 2.2.3.6.8 1 1.3 1.3.5.3 1.1.4 1.7.4.8 0 1.4-.2 1.8-.5.5-.4.9-.8 1.2-1.3l1.4.7c-.4.8-1 1.4-1.7 1.9-.9.6-1.8.8-2.9.8zm6.7-.3V86.1h1.6v1.6h.1c.1-.4.4-.7.7-1 .3-.3.7-.5 1.1-.7s.8-.2 1.2-.2h.7c.2 0 .3.1.5.2v1.8c-.2-.1-.5-.2-.7-.2-.2-.1-.5-.1-.7-.1-.5 0-1 .1-1.4.4-.4.3-.7.7-1 1.1-.2.5-.4 1-.4 1.5v5.7h-1.7zm10.4.3c-.8 0-1.4-.1-2-.4s-1-.7-1.3-1.2c-.3-.5-.5-1.1-.5-1.8 0-.8.2-1.4.6-1.9.4-.5.9-.9 1.5-1.2.7-.3 1.4-.4 2.2-.4.4 0 .9 0 1.2.1s.7.2 1 .3c.3.1.5.2.7.3v-.6c0-.8-.3-1.4-.8-1.8-.5-.5-1.2-.7-2-.7-.6 0-1.1.1-1.6.4-.5.2-.9.6-1.1 1l-1.3-1c.3-.4.6-.7 1-1 .4-.3.9-.5 1.4-.7.5-.2 1.1-.2 1.6-.2 1.4 0 2.5.4 3.2 1.1.8.7 1.2 1.7 1.2 3v6.5h-1.6v-1.5h-.1c-.2.3-.4.6-.7.8s-.7.5-1.1.7c-.5.2-1 .2-1.5.2zm.1-1.5c.6 0 1.1-.1 1.6-.4.5-.3.9-.7 1.2-1.2.3-.5.5-1 .5-1.6-.3-.2-.7-.4-1.2-.5s-1-.2-1.5-.2c-1 0-1.7.2-2.1.6-.4.4-.7.9-.7 1.5s.2 1 .6 1.4 1 .4 1.6.4zm11.8 1.5c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-2 .7-2.8.4-.8 1.1-1.5 1.8-1.9.8-.5 1.7-.7 2.7-.7 1.1 0 2.1.3 2.8.8.7.5 1.3 1.2 1.6 2l-1.5.6c-.2-.6-.6-1.1-1.1-1.4-.5-.3-1.1-.5-1.8-.5-.6 0-1.2.2-1.7.5s-.9.8-1.2 1.4c-.3.6-.5 1.3-.5 2 0 .8.2 1.4.5 2 .3.6.7 1 1.2 1.4.5.3 1.1.5 1.7.5.7 0 1.3-.2 1.9-.5s.9-.8 1.2-1.4l1.5.6c-.3.8-.9 1.5-1.6 2s-1.9.8-3 .8zm5.5-10.5h6v1.5h-6v-1.5zm1.7 7.5V83.3h1.7v10c0 .5.1.9.3 1.2s.6.4 1.1.4c.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8s-.7-1.3-.7-2.2zm6.5 2.7V86.1h1.7v10.2h-1.7zm.9-12c-.3 0-.6-.1-.9-.4s-.4-.5-.4-.9c0-.3.1-.6.4-.9.2-.2.5-.4.9-.4.3 0 .6.1.9.4.2.2.4.5.4.9 0 .3-.1.6-.4.9-.3.2-.6.4-.9.4zm8.1 12.3c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-1.9.7-2.8.4-.8 1.1-1.5 1.8-2 .8-.5 1.7-.7 2.7-.7 1 0 1.9.2 2.7.7.8.5 1.4 1.1 1.9 2s.7 1.7.7 2.7c0 1-.2 1.9-.7 2.8-.4.8-1.1 1.5-1.9 1.9-.8.6-1.7.8-2.7.8zm0-1.5c.6 0 1.2-.2 1.7-.5s1-.8 1.3-1.3c.3-.6.5-1.3.5-2.1s-.2-1.5-.5-2.1-.8-1-1.3-1.3c-.5-.3-1.1-.5-1.7-.5-.6 0-1.2.2-1.7.5s-1 .7-1.3 1.3-.5 1.3-.5 2.1.2 1.5.5 2.1c.3.6.8 1 1.3 1.3.5.4 1.1.5 1.7.5zm7 1.2V86.1h1.6v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V90c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7h-1.7zM143 86.1h6v1.5h-6v-1.5zm1.7 7.5V83.3h1.7v10c0 .5.1.9.3 1.2s.6.4 1.1.4c.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.6-.7-1.3-.7-2.2zm10.5 3c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-1.9.7-2.8.4-.8 1.1-1.5 1.8-2 .8-.5 1.7-.7 2.7-.7 1 0 1.9.2 2.7.7.8.5 1.4 1.1 1.9 2 .4.8.7 1.7.7 2.7 0 1-.2 1.9-.7 2.8-.4.8-1.1 1.5-1.9 1.9-.8.6-1.7.8-2.7.8zm0-1.5c.6 0 1.2-.2 1.7-.5s1-.8 1.3-1.3c.3-.6.5-1.3.5-2.1s-.2-1.5-.5-2.1c-.3-.6-.8-1-1.3-1.3-.5-.3-1.1-.5-1.7-.5-.6 0-1.2.2-1.7.5s-1 .7-1.3 1.3c-.3.6-.5 1.3-.5 2.1s.2 1.5.5 2.1c.3.6.8 1 1.3 1.3.5.4 1.1.5 1.7.5zm12.2 1.2V82h2.1l7.2 11.4h.1l-.1-2.8V82h1.7v14.3h-1.8l-7.5-11.9h-.1l.1 2.8v9.2h-1.7zm18.2.3c-1 0-1.9-.2-2.6-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.6-1.7-.6-2.8 0-1 .2-1.9.6-2.7.4-.8 1-1.5 1.7-2s1.6-.8 2.6-.8 1.9.2 2.6.7c.7.4 1.3 1.1 1.7 1.8.4.8.6 1.7.6 2.7v.5h-8.8V90h7c0-.3-.1-.6-.2-.9-.1-.3-.3-.6-.5-.9-.2-.3-.6-.5-.9-.7-.4-.2-.8-.3-1.4-.3-.7 0-1.2.2-1.7.5s-.8.8-1.1 1.4c-.3.6-.4 1.2-.4 2 0 .9.2 1.6.5 2.2.3.6.8 1 1.3 1.3.5.3 1.1.4 1.7.4.8 0 1.4-.2 1.8-.5.5-.4.9-.8 1.2-1.3l1.4.7c-.4.8-1 1.4-1.7 1.9-1 .6-1.9.8-3 .8zm5.5-.3 4.1-5.9h.2l2.9-4.3h2l-4 5.6h-.1l-3.1 4.6h-2zm.1-10.2h1.9l3.2 4.5h.1l4 5.7h-2l-3-4.5h-.1l-4.1-5.7zm9.9 0h6v1.5h-6v-1.5zm1.8 7.5V83.3h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.6-.7-1.3-.7-2.2zm11.2 2.7V82h4.8c.8 0 1.5.2 2.2.5.7.4 1.2.8 1.6 1.5.4.6.6 1.4.6 2.2 0 .8-.2 1.6-.6 2.2-.4.6-.9 1.1-1.6 1.5-.7.4-1.4.5-2.2.5H215v-1.6h4c.6 0 1-.1 1.4-.4.4-.3.7-.6.9-1 .2-.4.3-.8.3-1.2s-.1-.8-.3-1.2c-.2-.4-.5-.7-.9-1-.4-.3-.9-.4-1.4-.4h-3.2v12.7h-1.7zm14.1.3c-.8 0-1.4-.1-2-.4s-1-.7-1.3-1.2-.5-1.1-.5-1.8c0-.8.2-1.4.6-1.9s.9-.9 1.5-1.2c.7-.3 1.4-.4 2.2-.4.4 0 .9 0 1.2.1s.7.2 1 .3c.3.1.5.2.7.3v-.6c0-.8-.3-1.4-.8-1.8-.5-.5-1.2-.7-2-.7-.6 0-1.1.1-1.6.4-.5.2-.9.6-1.1 1l-1.3-1c.3-.4.6-.7 1-1 .4-.3.9-.5 1.4-.7s1.1-.2 1.6-.2c1.4 0 2.5.4 3.2 1.1.8.7 1.2 1.7 1.2 3v6.5h-1.6v-1.5h-.1c-.2.3-.4.6-.7.8s-.7.5-1.1.7c-.6.2-1 .2-1.5.2zm.1-1.5c.6 0 1.1-.1 1.6-.4.5-.3.9-.7 1.2-1.2.3-.5.5-1 .5-1.6-.3-.2-.7-.4-1.2-.5s-1-.2-1.5-.2c-1 0-1.7.2-2.1.6-.4.4-.7.9-.7 1.5s.2 1 .6 1.4 1 .4 1.6.4zm7.4 1.2V86.1h1.7v10.2h-1.7zm.8-12c-.3 0-.6-.1-.9-.4s-.4-.5-.4-.9c0-.3.1-.6.4-.9.2-.2.5-.4.9-.4.3 0 .6.1.9.4.2.2.4.5.4.9 0 .3-.1.6-.4.9-.2.2-.5.4-.9.4zm3.5 12V86.1h1.6v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V90c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7H240zm10.1-10.2h6v1.5h-6v-1.5zm1.7 7.5V83.3h1.7v10c0 .5.1.9.3 1.2s.6.4 1.1.4c.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8s-.7-1.3-.7-2.2zM96 172.8c-2.4 0-4.3 1.9-4.3 4.3 0 2 1.4 3.7 3.3 4.2v20.1h2v-20.1c1.9-.5 3.3-2.1 3.3-4.2 0-2.3-1.9-4.3-4.3-4.3zM201.6 172.6c-2.4 0-4.3 1.9-4.3 4.3 0 2 1.4 3.7 3.3 4.2v19.8h2v-19.8c1.9-.5 3.3-2.1 3.3-4.2 0-2.4-1.9-4.3-4.3-4.3z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;
  &lt;svg title=&quot;A diagram of the INP thresholds. An INP at or below 200 milliseconds is considered good. Between 200 and 500 milliseconds suggests a page&#39;s responsiveness needs improvement. Anything over 500 milliseconds means that a page&#39;s responsiveness is poor.&quot; class=&quot;inp-desktop&quot; version=&quot;1.1&quot; id=&quot;Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; x=&quot;0&quot; y=&quot;0&quot; viewBox=&quot;0 0 658.4 113.6&quot; style=&quot;enable-background:new 0 0 658.4 113.6&quot; xml:space=&quot;preserve&quot;&gt;&lt;style&gt;.st0{fill: #2979FF} v.st1{fill-rule: evenodd;clip-rule: evenodd;fill: #0CCE6B} .st2 {fill: #191919} .st3{fill-rule: evenodd;clip-rule: evenodd;fill: #FFA400} .st4{fill-rule: evenodd;clip-rule: evenodd;fill: #FF4E42} @media screen and (prefers-color-scheme: light){.st2{fill: #191919}} @media screen and (prefers-color-scheme: dark){.st2{fill: #fff}} [data-user-theme=dark] .st2{fill: #fff}&lt;/style&gt;&lt;path class=&quot;st0&quot; d=&quot;M30.2 68.7V0h13v68.7h-13zm28.7 0V0H74l27.7 46.1h.8l-.8-13.2V0h12.9v68.7H101L71.7 20.1h-.8l.8 13.2v35.4H58.9zm71.3 0V0h24.2c4.4 0 8.4.9 11.9 2.7 3.5 1.8 6.3 4.4 8.4 7.6 2.1 3.3 3.1 7 3.1 11.3 0 4.3-1 8.1-3.1 11.4-2.1 3.3-4.9 5.8-8.4 7.7-3.5 1.8-7.5 2.7-11.9 2.7h-17V31.2h17.4c2.2 0 4.1-.4 5.7-1.3 1.5-.9 2.7-2.1 3.5-3.5.8-1.4 1.2-3 1.2-4.7 0-1.7-.4-3.2-1.2-4.6-.8-1.4-1.9-2.6-3.5-3.5-1.5-.9-3.4-1.3-5.7-1.3h-11.6v56.5h-13z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st1&quot; d=&quot;M303.2 14.9h115.2v43.2H303.2V14.9z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M345.3 41.5c-.7 0-1.3-.1-1.9-.4-.6-.2-1.1-.6-1.6-1s-.8-1-1.1-1.6c-.3-.6-.4-1.3-.4-2s.1-1.4.4-2c.3-.6.6-1.1 1.1-1.6.5-.5 1-.8 1.6-1 .6-.2 1.2-.4 1.9-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1l-1 1c-.2-.2-.4-.4-.7-.6-.3-.2-.5-.3-.9-.4-.3-.1-.6-.1-1-.1-.5 0-.9.1-1.3.3-.4.2-.8.4-1.1.7-.3.3-.6.7-.8 1.1-.2.4-.3.9-.3 1.5s.1 1 .3 1.5c.2.4.5.8.8 1.1.3.3.7.6 1.1.7.4.2.9.2 1.3.2s.8-.1 1.2-.2c.4-.1.7-.3 1-.5.3-.2.5-.5.7-.8.2-.3.3-.7.3-1.1h-3.3v-1.3h4.6v.8c0 .7-.1 1.3-.4 1.9-.2.6-.6 1-1 1.5-.4.4-.9.7-1.5.9-.3.2-.9.3-1.6.3zm10.5 0c-.7 0-1.4-.1-2-.4-.6-.3-1.1-.6-1.6-1.1-.4-.5-.8-1-1-1.6-.2-.6-.4-1.2-.4-1.9s.1-1.3.4-1.9c.2-.6.6-1.1 1-1.6s1-.8 1.6-1.1c.6-.3 1.3-.4 2-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1.5.5.8 1 1 1.6.2.6.4 1.2.4 1.9s-.1 1.3-.4 1.9c-.2.6-.6 1.1-1 1.6s-1 .8-1.6 1.1-1.2.4-2 .4zm0-1.4c.6 0 1.2-.2 1.8-.5.5-.3.9-.7 1.2-1.3s.5-1.2.5-1.9-.2-1.3-.5-1.9-.7-1-1.2-1.3c-.5-.3-1.1-.5-1.8-.5-.6 0-1.2.2-1.8.5-.5.3-.9.7-1.2 1.3s-.5 1.2-.5 1.9.2 1.3.5 1.9.7 1 1.2 1.3c.6.4 1.2.5 1.8.5zm11 1.4c-.7 0-1.4-.1-2-.4-.6-.3-1.1-.6-1.6-1.1-.4-.5-.8-1-1-1.6-.2-.6-.4-1.2-.4-1.9s.1-1.3.4-1.9c.2-.6.6-1.1 1-1.6s1-.8 1.6-1.1c.6-.3 1.3-.4 2-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1.5.5.8 1 1 1.6.2.6.4 1.2.4 1.9s-.1 1.3-.4 1.9c-.2.6-.6 1.1-1 1.6s-1 .8-1.6 1.1-1.3.4-2 .4zm0-1.4c.6 0 1.2-.2 1.8-.5.5-.3.9-.7 1.2-1.3s.5-1.2.5-1.9-.2-1.3-.5-1.9-.7-1-1.2-1.3c-.5-.3-1.1-.5-1.8-.5-.6 0-1.2.2-1.8.5-.5.3-.9.7-1.2 1.3s-.5 1.2-.5 1.9.2 1.3.5 1.9.7 1 1.2 1.3c.6.4 1.2.5 1.8.5zm6.6 1.2v-9.5h3c1 0 1.9.2 2.6.6.7.4 1.3 1 1.7 1.7s.6 1.5.6 2.5c0 .9-.2 1.8-.6 2.5s-1 1.3-1.7 1.7c-.7.4-1.6.6-2.6.6h-3zm1.5-1.4h1.5c.7 0 1.3-.1 1.8-.4.5-.3.9-.7 1.2-1.2.3-.5.4-1.1.4-1.8s-.1-1.3-.4-1.8c-.3-.5-.7-.9-1.2-1.2-.5-.3-1.1-.4-1.8-.4h-1.5v6.8z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st3&quot; d=&quot;M418.4 14.9h124.8v43.2H418.4V14.9z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M460.8 33.3v-9.5h1.7l4.3 7h.1l-.1-1.8v-5.2h1.5v9.5h-1.5l-4.5-7.4h-.1l.1 1.8v5.5h-1.5zm9.7 0v-9.5h5.8v1.4H472V32h4.3v1.4h-5.8zm.7-4.1v-1.4h4.6v1.4h-4.6zm6.9 4.1v-9.5h5.8v1.4h-4.3V32h4.3v1.4h-5.8zm.8-4.1v-1.4h4.6v1.4h-4.6zm6.8 4.1v-9.5h3c1 0 1.9.2 2.6.6.7.4 1.3 1 1.7 1.7s.6 1.5.6 2.5c0 .9-.2 1.8-.6 2.5s-1 1.3-1.7 1.7c-.7.4-1.6.6-2.6.6h-3zm1.5-1.4h1.5c.7 0 1.3-.1 1.8-.4.5-.3.9-.7 1.2-1.2.3-.5.4-1.1.4-1.8s-.1-1.3-.4-1.8c-.3-.5-.7-.9-1.2-1.2-.5-.3-1.1-.4-1.8-.4h-1.5v6.8zm10.9 1.6c-.5 0-1-.1-1.5-.3-.5-.2-.9-.5-1.2-.9-.3-.4-.6-.9-.8-1.5l1.4-.6c.1.5.4.9.8 1.3.4.3.8.5 1.3.5.3 0 .6-.1.8-.2.3-.1.5-.3.6-.5.2-.2.2-.5.2-.8 0-.3-.1-.5-.2-.7-.1-.2-.3-.4-.6-.5-.3-.2-.7-.3-1.1-.5l-.6-.2c-.3-.1-.5-.2-.8-.4-.3-.1-.5-.3-.7-.5-.2-.2-.4-.5-.5-.7-.1-.3-.2-.6-.2-1 0-.5.1-.9.4-1.3.2-.4.6-.7 1-.9.4-.2 1-.4 1.6-.4.6 0 1.1.1 1.5.3.4.2.7.5 1 .8.2.3.4.6.5.9l-1.3.6c-.1-.2-.2-.4-.3-.5-.1-.2-.3-.3-.5-.4-.2-.1-.5-.2-.8-.2-.3 0-.5.1-.8.2-.2.1-.4.2-.6.4-.1.2-.2.4-.2.6 0 .3.1.6.4.8s.7.4 1.2.6l.6.2c.3.1.6.2.9.4.3.1.6.3.8.6.2.2.4.5.6.8.1.3.2.7.2 1.2s-.1.9-.3 1.3c-.2.4-.4.6-.8.9-.3.2-.7.4-1 .5-.3 0-.7.1-1 .1zM434.4 49.3v-9.5h1.5v9.5h-1.5zm3.6 0v-9.5h2l2.8 7.3h.1l2.8-7.3h2v9.5h-1.4v-5.4l.1-1.7h-.1l-2.8 7.1h-1.2l-2.8-7.1h-.1l.1 1.7v5.4H438zm11.7 0v-9.5h3.3c.6 0 1.1.1 1.6.4.5.2.9.6 1.1 1 .3.4.4.9.4 1.5s-.1 1.1-.4 1.5c-.3.4-.7.8-1.1 1-.5.2-1 .4-1.6.4h-2.5v-1.4h2.5c.4 0 .7-.1.9-.2.2-.1.4-.3.5-.6.1-.2.2-.5.2-.8 0-.3-.1-.5-.2-.7-.1-.2-.3-.4-.5-.6-.2-.2-.5-.2-.9-.2h-1.8v8.2h-1.5zm8 0v-9.5h3.3c.6 0 1.1.1 1.6.4.5.2.8.6 1.1 1s.4.9.4 1.5c0 .4-.1.8-.2 1.1s-.4.7-.7.9c-.3.3-.6.5-1 .6-.4.1-.9.2-1.4.2h-2.3v-1.3h2.5c.3 0 .6-.1.8-.2.2-.1.4-.3.6-.6.2-.2.2-.5.2-.8 0-.3-.1-.5-.2-.7-.1-.2-.3-.4-.5-.6-.2-.1-.5-.2-.9-.2h-1.9v8.2h-1.4zm2.2-4.4h1.7l3 4.3v.1h-1.7l-3-4.4zm10.3 4.6c-.7 0-1.4-.1-2-.4-.6-.3-1.1-.6-1.6-1.1-.4-.5-.8-1-1-1.6-.2-.6-.4-1.2-.4-1.9s.1-1.3.4-1.9c.2-.6.6-1.1 1-1.6s1-.8 1.6-1.1c.6-.3 1.3-.4 2-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1.5.5.8 1 1 1.6.2.6.4 1.2.4 1.9s-.1 1.3-.4 1.9c-.2.6-.6 1.1-1 1.6s-1 .8-1.6 1.1c-.6.3-1.2.4-2 .4zm0-1.4c.6 0 1.2-.2 1.8-.5.5-.3.9-.7 1.2-1.3.3-.5.5-1.2.5-1.9s-.2-1.3-.5-1.9c-.3-.5-.7-1-1.2-1.3-.5-.3-1.1-.5-1.8-.5s-1.2.2-1.8.5c-.5.3-.9.7-1.2 1.3-.3.5-.5 1.2-.5 1.9s.2 1.3.5 1.9c.3.5.7 1 1.2 1.3.6.4 1.2.5 1.8.5zm8.8 1.2-3.4-9.5h1.6l2.2 6.3.3 1.1h.1l.4-1.1 2.2-6.3h1.6l-3.5 9.5H479zm6.2 0v-9.5h5.8v1.4h-4.3V48h4.3v1.4h-5.8zm.8-4.1v-1.4h4.6v1.4H486zm6.8 4.1v-9.5h2l2.8 7.3h.1l2.8-7.3h2v9.5H501v-5.4l.1-1.7h-.1l-2.8 7.1H497l-2.8-7.1h-.1l.1 1.7v5.4h-1.4zm11.8 0v-9.5h5.8v1.4h-4.3V48h4.3v1.4h-5.8zm.8-4.1v-1.4h4.6v1.4h-4.6zm6.8 4.1v-9.5h1.7l4.3 7h.1l-.1-1.8v-5.2h1.5v9.5h-1.5l-4.5-7.4h-.1l.1 1.8v5.5h-1.5zm11.7 0v-8.8h1.5v8.8h-1.5zm-2.7-8.2v-1.4h6.8v1.4h-6.8z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st4&quot; d=&quot;M543.2 14.9h115.2v43.2H543.2V14.9z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;st2&quot; d=&quot;M582.9 41.3v-9.5h3.3c.6 0 1.1.1 1.6.4.5.2.9.6 1.1 1 .3.4.4.9.4 1.5s-.1 1.1-.4 1.5c-.3.4-.7.8-1.1 1-.5.2-1 .4-1.6.4h-2.5v-1.4h2.5c.4 0 .7-.1.9-.2.2-.1.4-.3.5-.6.1-.2.2-.5.2-.8 0-.3-.1-.5-.2-.7-.1-.2-.3-.4-.5-.6-.2-.2-.5-.2-.9-.2h-1.8v8.2h-1.5zm12.3.2c-.7 0-1.4-.1-2-.4-.6-.3-1.1-.6-1.6-1.1-.4-.5-.8-1-1-1.6-.2-.6-.4-1.2-.4-1.9s.1-1.3.4-1.9c.2-.6.6-1.1 1-1.6s1-.8 1.6-1.1c.6-.3 1.3-.4 2-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1.5.5.8 1 1 1.6.2.6.4 1.2.4 1.9s-.1 1.3-.4 1.9c-.2.6-.6 1.1-1 1.6s-1 .8-1.6 1.1c-.7.3-1.3.4-2 .4zm0-1.4c.6 0 1.2-.2 1.8-.5.5-.3.9-.7 1.2-1.3.3-.5.5-1.2.5-1.9s-.2-1.3-.5-1.9c-.3-.5-.7-1-1.2-1.3-.5-.3-1.1-.5-1.8-.5-.6 0-1.2.2-1.8.5-.5.3-.9.7-1.2 1.3-.3.5-.5 1.2-.5 1.9s.2 1.3.5 1.9c.3.5.7 1 1.2 1.3.6.4 1.1.5 1.8.5zm10.9 1.4c-.7 0-1.4-.1-2-.4-.6-.3-1.1-.6-1.6-1.1-.4-.5-.8-1-1-1.6-.2-.6-.4-1.2-.4-1.9s.1-1.3.4-1.9c.2-.6.6-1.1 1-1.6s1-.8 1.6-1.1c.6-.3 1.3-.4 2-.4s1.4.1 2 .4c.6.2 1.1.6 1.6 1.1.5.5.8 1 1 1.6.2.6.4 1.2.4 1.9s-.1 1.3-.4 1.9c-.2.6-.6 1.1-1 1.6s-1 .8-1.6 1.1c-.6.3-1.3.4-2 .4zm0-1.4c.6 0 1.2-.2 1.8-.5.5-.3.9-.7 1.2-1.3.3-.5.5-1.2.5-1.9s-.2-1.3-.5-1.9c-.3-.5-.7-1-1.2-1.3-.5-.3-1.1-.5-1.8-.5s-1.2.2-1.8.5c-.5.3-.9.7-1.2 1.3-.3.5-.5 1.2-.5 1.9s.2 1.3.5 1.9c.3.5.7 1 1.2 1.3.6.4 1.2.5 1.8.5zm6.7 1.2v-9.5h3.3c.6 0 1.1.1 1.6.4.5.2.8.6 1.1 1s.4.9.4 1.5c0 .4-.1.8-.2 1.1s-.4.7-.7.9c-.3.3-.6.5-1 .6-.4.1-.9.2-1.4.2h-2.3v-1.3h2.5c.3 0 .6-.1.8-.2.2-.1.4-.3.6-.6.2-.2.2-.5.2-.8 0-.3-.1-.5-.2-.7-.1-.2-.3-.4-.5-.6-.2-.1-.5-.2-.9-.2h-1.9v8.2h-1.4zm2.2-4.4h1.7l3 4.3v.1H618l-3-4.4zM517.7 102.9c-.6 0-1.1-.1-1.7-.3-.6-.2-1-.6-1.5-1-.4-.5-.7-1.1-.9-1.8l1.7-.7c.2.6.4 1.1.8 1.5.4.4.9.6 1.6.6.7 0 1.2-.2 1.6-.6.4-.4.7-1 .7-1.6 0-.7-.2-1.2-.6-1.6-.4-.4-1-.7-1.6-.7-.4 0-.8.1-1.1.2-.3.2-.6.4-.8.7l-1.8-.8.7-6h6.4v1.7h-4.9l-.4 3.2h.1c.3-.2.6-.4.9-.5.4-.1.8-.2 1.3-.2.7 0 1.3.2 1.9.5.6.3 1 .8 1.4 1.4.4.6.5 1.3.5 2 0 .8-.2 1.5-.5 2.1-.4.6-.8 1.1-1.5 1.4-.7.3-1.5.5-2.3.5zm10.8 0c-.7 0-1.4-.2-2-.5-.6-.3-1.1-.8-1.5-1.3-.4-.6-.8-1.2-1-2-.2-.8-.3-1.6-.3-2.4 0-.9.1-1.7.3-2.5.2-.8.6-1.4 1-2 .4-.6.9-1 1.5-1.3.6-.3 1.3-.5 2-.5.8 0 1.4.2 2 .5.6.3 1.1.8 1.5 1.3.4.6.8 1.2 1 2 .2.8.3 1.6.3 2.5 0 .9-.1 1.7-.3 2.4-.2.8-.5 1.4-1 2-.4.6-.9 1-1.5 1.3-.6.3-1.2.5-2 .5zm0-1.8c.6 0 1.1-.2 1.6-.6.4-.4.8-.9 1-1.6.2-.7.4-1.4.4-2.2 0-.8-.1-1.6-.4-2.3-.2-.7-.6-1.2-1-1.6-.4-.4-1-.6-1.6-.6-.6 0-1.2.2-1.6.6-.4.4-.8.9-1 1.6-.2.7-.4 1.4-.4 2.3 0 .8.1 1.6.4 2.2.2.7.6 1.2 1 1.6.5.4 1 .6 1.6.6zm11.4 1.8c-.7 0-1.4-.2-2-.5-.6-.3-1.1-.8-1.5-1.3-.4-.6-.8-1.2-1-2-.2-.8-.3-1.6-.3-2.4 0-.9.1-1.7.3-2.5.2-.8.6-1.4 1-2 .4-.6.9-1 1.5-1.3.6-.3 1.3-.5 2-.5.8 0 1.4.2 2 .5.6.3 1.1.8 1.5 1.3.4.6.8 1.2 1 2 .2.8.3 1.6.3 2.5 0 .9-.1 1.7-.3 2.4-.2.8-.5 1.4-1 2-.4.6-.9 1-1.5 1.3-.5.3-1.2.5-2 .5zm.1-1.8c.6 0 1.1-.2 1.6-.6.4-.4.8-.9 1-1.6.2-.7.4-1.4.4-2.2 0-.8-.1-1.6-.4-2.3-.2-.7-.6-1.2-1-1.6-.4-.4-1-.6-1.6-.6-.6 0-1.2.2-1.6.6-.4.4-.8.9-1 1.6-.2.7-.4 1.4-.4 2.3 0 .8.1 1.6.4 2.2.2.7.6 1.2 1 1.6.4.4.9.6 1.6.6zm10.8 1.5v-8.8h1.8V95h.1c.2-.3.4-.5.7-.8s.6-.4.9-.5c.4-.1.7-.2 1.1-.2.7 0 1.2.2 1.7.5s.8.7 1 1.2c.3-.5.7-.8 1.2-1.2.5-.3 1.1-.5 1.8-.5 1 0 1.8.3 2.3 1 .5.6.8 1.5.8 2.5v5.7h-1.9v-5.4c0-.7-.2-1.2-.5-1.5-.3-.3-.7-.5-1.3-.5-.4 0-.8.1-1.1.4-.3.2-.6.6-.8 1s-.3.9-.3 1.3v4.7h-1.9v-5.4c0-.7-.2-1.2-.5-1.5-.3-.3-.8-.5-1.3-.5-.4 0-.8.1-1.1.4-.3.2-.6.6-.7 1s-.3.9-.3 1.3v4.7h-1.7zm18.6.3c-.7 0-1.3-.1-1.8-.3-.5-.2-.9-.5-1.3-.9-.3-.4-.6-.8-.7-1.2l1.7-.7c.2.5.5.8.9 1.1.4.2.8.4 1.3.4s.9-.1 1.2-.2c.3-.2.5-.4.5-.8 0-.2-.1-.5-.2-.6s-.4-.3-.6-.4l-.9-.3-1.1-.2c-.4-.1-.8-.3-1.2-.5-.4-.2-.7-.5-.9-.9-.2-.4-.3-.8-.3-1.2 0-.5.2-1 .5-1.4.3-.4.7-.7 1.2-.9.5-.2 1.1-.3 1.7-.3.6 0 1.1.1 1.5.2.5.1.9.3 1.2.6.3.3.6.6.8 1l-1.6.7c-.2-.4-.5-.7-.8-.8-.3-.2-.7-.2-1.1-.2-.4 0-.8.1-1.1.3-.3.2-.4.4-.4.7 0 .3.1.5.4.7.3.2.6.3 1 .4l1.3.3c.9.2 1.5.6 2 1 .4.4.7 1 .7 1.6 0 .6-.2 1.1-.5 1.5-.3.4-.8.7-1.3 1-.8.2-1.5.3-2.1.3zM389.2 102.6v-1.8l.4-.4.9-.9c.4-.4.7-.8 1.1-1.2l1.1-1.1.8-.8c.3-.3.6-.6.8-.9.2-.3.3-.5.4-.8.1-.2.1-.5.1-.8 0-.3-.1-.6-.2-.8-.1-.3-.4-.5-.7-.6-.3-.2-.6-.2-1.1-.2-.4 0-.7.1-1 .2-.3.2-.5.4-.7.6-.2.2-.3.5-.3.7l-1.7-.7c.1-.3.2-.6.4-.9.2-.3.4-.6.8-.9.3-.3.7-.5 1.1-.7.4-.2.9-.3 1.5-.3.8 0 1.4.2 2 .5.6.3 1 .7 1.3 1.2.3.5.5 1.1.5 1.7 0 .5-.1 1-.3 1.5-.2.5-.4.9-.7 1.3-.3.4-.6.7-.9 1-.2.1-.4.3-.6.6-.2.2-.5.5-.7.8l-.8.8-.7.7-.4.4h5.2v1.7h-7.6zm14.2.3c-.7 0-1.4-.2-2-.5-.6-.3-1.1-.8-1.5-1.3-.4-.6-.8-1.2-1-2-.2-.8-.3-1.6-.3-2.4 0-.9.1-1.7.3-2.5.2-.8.6-1.4 1-2 .4-.6.9-1 1.5-1.3.6-.3 1.3-.5 2-.5.8 0 1.4.2 2 .5.6.3 1.1.8 1.5 1.3.4.6.8 1.2 1 2 .2.8.3 1.6.3 2.5 0 .9-.1 1.7-.3 2.4-.2.8-.5 1.4-1 2-.4.6-.9 1-1.5 1.3-.5.3-1.2.5-2 .5zm0-1.8c.6 0 1.1-.2 1.6-.6.4-.4.8-.9 1-1.6.2-.7.4-1.4.4-2.2 0-.8-.1-1.6-.4-2.3-.2-.7-.6-1.2-1-1.6-.4-.4-1-.6-1.6-.6-.6 0-1.2.2-1.6.6-.4.4-.8.9-1 1.6-.2.7-.4 1.4-.4 2.3 0 .8.1 1.6.4 2.2.2.7.6 1.2 1 1.6.5.4 1 .6 1.6.6zm11.5 1.8c-.7 0-1.4-.2-2-.5-.6-.3-1.1-.8-1.5-1.3-.4-.6-.8-1.2-1-2-.2-.8-.3-1.6-.3-2.4 0-.9.1-1.7.3-2.5.2-.8.6-1.4 1-2 .4-.6.9-1 1.5-1.3.6-.3 1.3-.5 2-.5.8 0 1.4.2 2 .5.6.3 1.1.8 1.5 1.3.4.6.8 1.2 1 2 .2.8.3 1.6.3 2.5 0 .9-.1 1.7-.3 2.4-.2.8-.5 1.4-1 2-.4.6-.9 1-1.5 1.3-.6.3-1.3.5-2 .5zm0-1.8c.6 0 1.1-.2 1.6-.6.4-.4.8-.9 1-1.6.2-.7.4-1.4.4-2.2 0-.8-.1-1.6-.4-2.3-.2-.7-.6-1.2-1-1.6-.4-.4-1-.6-1.6-.6-.6 0-1.2.2-1.6.6-.4.4-.8.9-1 1.6-.2.7-.4 1.4-.4 2.3 0 .8.1 1.6.4 2.2.2.7.6 1.2 1 1.6.4.4.9.6 1.6.6zm10.8 1.5v-8.8h1.8V95h.1c.2-.3.4-.5.7-.8s.6-.4.9-.5c.4-.1.7-.2 1.1-.2.7 0 1.2.2 1.7.5s.8.7 1 1.2c.3-.5.7-.8 1.2-1.2.5-.3 1.1-.5 1.8-.5 1 0 1.8.3 2.3 1 .5.6.8 1.5.8 2.5v5.7h-1.9v-5.4c0-.7-.2-1.2-.5-1.5-.3-.3-.7-.5-1.3-.5-.4 0-.8.1-1.1.4-.3.2-.6.6-.8 1s-.3.9-.3 1.3v4.7h-1.9v-5.4c0-.7-.2-1.2-.5-1.5-.3-.3-.8-.5-1.3-.5-.4 0-.8.1-1.1.4-.3.2-.6.6-.7 1s-.3.9-.3 1.3v4.7h-1.7zm18.6.3c-.7 0-1.3-.1-1.8-.3-.5-.2-.9-.5-1.3-.9-.3-.4-.6-.8-.7-1.2l1.7-.7c.2.5.5.8.9 1.1.4.2.8.4 1.3.4s.9-.1 1.2-.2c.3-.2.5-.4.5-.8 0-.2-.1-.5-.2-.6-.2-.2-.4-.3-.6-.4l-.9-.3-1.1-.2c-.4-.1-.8-.3-1.2-.5-.4-.2-.7-.5-.9-.9-.2-.4-.3-.8-.3-1.2 0-.5.2-1 .5-1.4.3-.4.7-.7 1.2-.9.5-.2 1.1-.3 1.7-.3.6 0 1.1.1 1.5.2.5.1.9.3 1.2.6.3.3.6.6.8 1l-1.6.7c-.2-.4-.5-.7-.8-.8-.3-.2-.7-.2-1.1-.2-.4 0-.8.1-1.1.3-.3.2-.4.4-.4.7 0 .3.1.5.4.7.3.2.6.3 1 .4l1.3.3c.9.2 1.5.6 2 1 .4.4.7 1 .7 1.6 0 .6-.2 1.1-.5 1.5-.3.4-.8.7-1.3 1-.8.2-1.4.3-2.1.3zM0 113.3V99h1.7v14.3H0zm4.6 0v-10.2h1.6v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V107c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7H4.6zm10-10.2h6v1.5h-6v-1.5zm1.8 7.5v-10.4h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.5-.5-.7-1.2-.7-2.1zm10.3 3c-1 0-1.9-.2-2.6-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.6-1.7-.6-2.8 0-1 .2-1.9.6-2.7.4-.8 1-1.5 1.7-2s1.6-.8 2.6-.8 1.9.2 2.6.7c.7.4 1.3 1.1 1.7 1.8.4.8.6 1.7.6 2.7v.5h-8.8V107h7c0-.3-.1-.6-.2-.9-.1-.3-.3-.6-.5-.9-.2-.3-.6-.5-.9-.7-.4-.2-.8-.3-1.4-.3-.7 0-1.2.2-1.7.5s-.8.8-1.1 1.4c-.3.6-.4 1.2-.4 2 0 .9.2 1.6.5 2.2.3.6.8 1 1.3 1.3.5.3 1.1.4 1.7.4.8 0 1.4-.2 1.8-.5.5-.4.9-.8 1.2-1.3l1.4.7c-.4.8-1 1.4-1.7 1.9-1 .5-1.9.8-3 .8zm6.7-.3v-10.2H35v1.6h.1c.1-.4.4-.7.7-1 .3-.3.7-.5 1.1-.7.4-.2.8-.2 1.2-.2h.7c.2 0 .3.1.5.2v1.8c-.2-.1-.5-.2-.7-.2-.2-.1-.5-.1-.7-.1-.5 0-1 .1-1.4.4-.4.3-.7.7-1 1.1-.2.5-.4 1-.4 1.5v5.7h-1.7zm10.4.3c-.8 0-1.4-.1-2-.4-.6-.3-1-.7-1.3-1.2-.3-.5-.5-1.1-.5-1.8 0-.8.2-1.4.6-1.9.4-.5.9-.9 1.5-1.2.7-.3 1.4-.4 2.2-.4.4 0 .9 0 1.2.1.4.1.7.2 1 .3.3.1.5.2.7.3v-.6c0-.8-.3-1.4-.8-1.8-.5-.5-1.2-.7-2-.7-.6 0-1.1.1-1.6.4-.5.2-.9.6-1.1 1l-1.3-1c.3-.4.6-.7 1-1 .4-.3.9-.5 1.4-.7.5-.2 1.1-.2 1.6-.2 1.4 0 2.5.4 3.2 1.1.8.7 1.2 1.7 1.2 3v6.5h-1.6v-1.5h-.1c-.2.3-.4.6-.7.8-.3.3-.7.5-1.1.7-.5.1-1 .2-1.5.2zm.1-1.5c.6 0 1.1-.1 1.6-.4.5-.3.9-.7 1.2-1.2.3-.5.5-1 .5-1.6-.3-.2-.7-.4-1.2-.5-.5-.1-1-.2-1.5-.2-1 0-1.7.2-2.1.6-.4.4-.7.9-.7 1.5s.2 1 .6 1.4c.4.2 1 .4 1.6.4zm11.7 1.5c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-2 .7-2.8.4-.8 1.1-1.5 1.8-1.9.8-.5 1.7-.7 2.7-.7 1.1 0 2.1.3 2.8.8.7.5 1.3 1.2 1.6 2l-1.5.6c-.2-.6-.6-1.1-1.1-1.4-.5-.3-1.1-.5-1.8-.5-.6 0-1.2.2-1.7.5s-.9.8-1.2 1.4c-.3.6-.5 1.3-.5 2 0 .8.2 1.4.5 2 .3.6.7 1 1.2 1.4.5.3 1.1.5 1.7.5.7 0 1.3-.2 1.9-.5.5-.3.9-.8 1.2-1.4l1.5.6c-.3.8-.9 1.5-1.6 2-.9.5-1.8.8-3 .8zm5.5-10.5h6v1.5h-6v-1.5zm1.8 7.5v-10.4h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.5-.7-1.2-.7-2.1zm6.5 2.7v-10.2h1.7v10.2h-1.7zm.9-12.1c-.3 0-.6-.1-.9-.4-.2-.2-.4-.5-.4-.9 0-.3.1-.6.4-.9.2-.2.5-.4.9-.4.3 0 .6.1.9.4.2.2.4.5.4.9 0 .3-.1.6-.4.9-.3.3-.6.4-.9.4zm8.1 12.4c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-1.9.7-2.8.4-.8 1.1-1.5 1.8-2 .8-.5 1.7-.7 2.7-.7 1 0 1.9.2 2.7.7.8.5 1.4 1.1 1.9 2 .4.8.7 1.7.7 2.7 0 1-.2 1.9-.7 2.8-.4.8-1.1 1.5-1.9 1.9-.8.5-1.7.8-2.7.8zm0-1.6c.6 0 1.2-.2 1.7-.5s1-.8 1.3-1.3c.3-.6.5-1.3.5-2.1s-.2-1.5-.5-2.1c-.3-.6-.8-1-1.3-1.3-.5-.3-1.1-.5-1.7-.5-.6 0-1.2.2-1.7.5s-1 .7-1.3 1.3c-.3.6-.5 1.3-.5 2.1s.2 1.5.5 2.1c.3.6.8 1 1.3 1.3.5.4 1.1.5 1.7.5zm7 1.3v-10.2H87v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V107c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7h-1.7zm15.1-10.2h6v1.5h-6v-1.5zm1.8 7.5v-10.4h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.5-.7-1.2-.7-2.1zm10.5 3c-1 0-1.9-.2-2.7-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.7-1.7-.7-2.8 0-1 .2-1.9.7-2.8.4-.8 1.1-1.5 1.8-2 .8-.5 1.7-.7 2.7-.7 1 0 1.9.2 2.7.7.8.5 1.4 1.1 1.9 2 .4.8.7 1.7.7 2.7 0 1-.2 1.9-.7 2.8-.4.8-1.1 1.5-1.9 1.9-.8.5-1.7.8-2.7.8zm0-1.6c.6 0 1.2-.2 1.7-.5s1-.8 1.3-1.3c.3-.6.5-1.3.5-2.1s-.2-1.5-.5-2.1c-.3-.6-.8-1-1.3-1.3-.5-.3-1.1-.5-1.7-.5-.6 0-1.2.2-1.7.5s-1 .7-1.3 1.3c-.3.6-.5 1.3-.5 2.1s.2 1.5.5 2.1c.3.6.8 1 1.3 1.3.5.4 1.1.5 1.7.5zm12.2 1.3V99h2.1l7.2 11.4h.1l-.1-2.8V99h1.7v14.3h-1.8l-7.5-11.9h-.1l.1 2.8v9.2H125zm18.2.3c-1 0-1.9-.2-2.6-.7-.8-.5-1.4-1.1-1.8-1.9-.4-.8-.6-1.7-.6-2.8 0-1 .2-1.9.6-2.7.4-.8 1-1.5 1.7-2s1.6-.8 2.6-.8 1.9.2 2.6.7c.7.4 1.3 1.1 1.7 1.8.4.8.6 1.7.6 2.7v.5h-8.8V107h7c0-.3-.1-.6-.2-.9-.1-.3-.3-.6-.5-.9-.2-.3-.6-.5-.9-.7-.4-.2-.8-.3-1.4-.3-.7 0-1.2.2-1.7.5s-.8.8-1.1 1.4c-.3.6-.4 1.2-.4 2 0 .9.2 1.6.5 2.2.3.6.8 1 1.3 1.3.5.3 1.1.4 1.7.4.8 0 1.4-.2 1.8-.5.5-.4.9-.8 1.2-1.3l1.4.7c-.4.8-1 1.4-1.7 1.9-1 .5-1.9.8-3 .8zm5.5-.3 4.1-5.9h.2l2.9-4.3h2l-4 5.6h-.1l-3.1 4.6h-2zm.1-10.2h1.9l3.2 4.5h.1l4 5.7h-2l-3-4.5h-.1l-4.1-5.7zm9.9 0h6v1.5h-6v-1.5zm1.8 7.5v-10.4h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.5-.7-1.2-.7-2.1zm11.2 2.7V99h4.8c.8 0 1.5.2 2.2.5.7.4 1.2.8 1.6 1.5.4.6.6 1.4.6 2.2 0 .8-.2 1.6-.6 2.2-.4.6-.9 1.1-1.6 1.5-.7.4-1.4.5-2.2.5h-3.9v-1.6h4c.6 0 1-.1 1.4-.4.4-.3.7-.6.9-1 .2-.4.3-.8.3-1.2 0-.4-.1-.8-.3-1.2-.2-.4-.5-.7-.9-1-.4-.3-.9-.4-1.4-.4h-3.2v12.7h-1.7zm14 .3c-.8 0-1.4-.1-2-.4-.6-.3-1-.7-1.3-1.2-.3-.5-.5-1.1-.5-1.8 0-.8.2-1.4.6-1.9.4-.5.9-.9 1.5-1.2.7-.3 1.4-.4 2.2-.4.4 0 .9 0 1.2.1.4.1.7.2 1 .3.3.1.5.2.7.3v-.6c0-.8-.3-1.4-.8-1.8-.5-.5-1.2-.7-2-.7-.6 0-1.1.1-1.6.4-.5.2-.9.6-1.1 1l-1.3-1c.3-.4.6-.7 1-1 .4-.3.9-.5 1.4-.7.5-.2 1.1-.2 1.6-.2 1.4 0 2.5.4 3.2 1.1.8.7 1.2 1.7 1.2 3v6.5h-1.6v-1.5h-.1c-.2.3-.4.6-.7.8-.3.3-.7.5-1.1.7-.5.1-.9.2-1.5.2zm.2-1.5c.6 0 1.1-.1 1.6-.4.5-.3.9-.7 1.2-1.2.3-.5.5-1 .5-1.6-.3-.2-.7-.4-1.2-.5-.5-.1-1-.2-1.5-.2-1 0-1.7.2-2.1.6-.4.4-.7.9-.7 1.5s.2 1 .6 1.4c.4.2 1 .4 1.6.4zm7.4 1.2v-10.2h1.7v10.2h-1.7zm.8-12.1c-.3 0-.6-.1-.9-.4-.2-.2-.4-.5-.4-.9 0-.3.1-.6.4-.9.2-.2.5-.4.9-.4.3 0 .6.1.9.4.2.2.4.5.4.9 0 .3-.1.6-.4.9-.3.3-.5.4-.9.4zm3.5 12.1v-10.2h1.6v1.5h.1c.3-.5.7-.9 1.3-1.3.6-.4 1.3-.5 2-.5 1.2 0 2.2.4 2.8 1.1.6.7 1 1.7 1 2.9v6.5h-1.7V107c0-1-.2-1.7-.7-2.1-.5-.4-1.1-.6-1.8-.6-.6 0-1.1.2-1.5.5-.4.3-.8.7-1 1.2-.2.5-.4 1-.4 1.6v5.7h-1.7zm10-10.2h6v1.5h-6v-1.5zm1.8 7.5v-10.4h1.7v10c0 .5.1.9.3 1.2.2.3.6.4 1.1.4.2 0 .4 0 .6-.1.2-.1.4-.2.5-.2v1.7c-.2.1-.4.1-.6.2-.2.1-.5.1-.8.1-.9 0-1.5-.2-2.1-.8-.4-.5-.7-1.2-.7-2.1zM418.1 55.2c-1.8 0-3.3 1.5-3.3 3.3 0 1.5 1 2.7 2.3 3.1V83h2V61.6c1.3-.4 2.3-1.7 2.3-3.1 0-1.8-1.5-3.3-3.3-3.3zM546.5 58.6c0-1.8-1.5-3.3-3.3-3.3s-3.3 1.5-3.3 3.3c0 1.5 1 2.7 2.3 3.1v21.2h2V61.7c1.3-.4 2.3-1.6 2.3-3.1z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;
&lt;/figure&gt;
&lt;p&gt;Depending on the website, there may be few to no interactions—such as pages of mostly text and images with few to no interactive elements. Or, in the case of websites such as in-browser text editors or games, there could be hundreds—even thousands—of interactions. In either case, where there&#39;s a high INP, the user experience is at risk.&lt;/p&gt;
&lt;p&gt;It takes time and effort to improve INP, but the reward is a better user experience. In this guide, a path to improving INP will be explored.&lt;/p&gt;
&lt;h2 id=&quot;figure-out-whats-causing-poor-inp&quot;&gt;Figure out what&#39;s causing poor INP &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#figure-out-whats-causing-poor-inp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finding ways to fix a poor INP can be difficult. To start, you have to know &lt;em&gt;which&lt;/em&gt; interactions tend to be responsible for the page&#39;s INP, out of all the interactions users have with the page. To do that, you&#39;ll need to first lean on field data, and &lt;em&gt;then&lt;/em&gt; test in the lab to figure out what&#39;s making an interaction slow.&lt;/p&gt;
&lt;h3 id=&quot;find-slow-interactions-in-the-field&quot;&gt;Find slow interactions in the field &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#find-slow-interactions-in-the-field&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Field data should be the first place you go to find slow interactions. The &lt;code&gt;web-vitals&lt;/code&gt; JavaScript library is one way to find these interactions, thanks in large part to its ability to attribute INP values to specific elements through its attribution build:&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 comment&quot;&gt;// Use the attribution build:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; onINP &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;web-vitals/attribution&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Example reporting function that&#39;s passed to web-vitals:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;report&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attribution &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attribution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attribution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventTarget&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Pass the reporting function to the INP reporter:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;onINP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;report&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-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;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Not every interaction can be attributed to a specific element. This is due to an underlying limitation of the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/PerformanceEventTiming&quot;&gt;Event Timing API&lt;/a&gt; where an &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Event/target&quot;&gt;event target&lt;/a&gt; may be absent if the element responsible for the interaction was disconnected from the DOM, or if the element was in the shadow DOM. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;When this code runs and you interact with a page, the console may report something similar to the following:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;INP&lt;br /&gt;248&lt;br /&gt;pointerdown&lt;br /&gt;#main-nav&gt;ul&gt;li&gt;button&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this case, you can see that tapping on a navigation menu toggle—which took 248 milliseconds—was responsible for the page&#39;s INP. At 248 milliseconds, this page&#39;s INP would be in the &amp;quot;needs improvement&amp;quot; category.&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 above code snippet is a simplistic example of working with the &lt;code&gt;web-vitals&lt;/code&gt; library. For an example that shows how to transmit data from the field to Google Analytics, read &lt;a href=&quot;https://github.com/GoogleChrome/web-vitals#send-attribution-data&quot;&gt;this section of the &lt;code&gt;web-vitals&lt;/code&gt; documentation&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Once you&#39;ve found elements that are responsible for slow interactions in the field, you can go into lab tools to start profiling them.&lt;/p&gt;
&lt;h3 id=&quot;reproduce-slow-interactions-in-the-lab&quot;&gt;Reproduce slow interactions in the lab &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#reproduce-slow-interactions-in-the-lab&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you have a better idea of what&#39;s responsible for slow interactions, you should profile them in the lab with a performance profiler such as the one available in Chrome&#39;s DevTools. To do so, take the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the page powering the interaction you want to test.&lt;/li&gt;
&lt;li&gt;Open Chrome&#39;s DevTools by pressing &lt;kbd&gt;Cmd&lt;/kbd&gt;+&lt;kbd&gt;Option&lt;/kbd&gt;+&lt;kbd&gt;I&lt;/kbd&gt; (&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;I&lt;/kbd&gt; on Windows and Linux).&lt;/li&gt;
&lt;li&gt;Go to the tab labeled &lt;strong&gt;Performance&lt;/strong&gt; in DevTools.&lt;/li&gt;
&lt;li&gt;Click the record button at the upper left hand corner of the empty performance profiler to start recording.&lt;/li&gt;
&lt;li&gt;Test the desired interaction on the page.&lt;/li&gt;
&lt;li&gt;Click the record button again to stop recording.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the profiler populates, you&#39;ll be able to see what work occurred to drive the interaction.&lt;/p&gt;
&lt;p&gt;There are some cues in the profiler you can use to narrow down where the interaction occurred, notably in the interactions track situated above the main thread track:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A depiction of tasks as related to interactions from Chrome&amp;#x27;s performance profiler. At top, an interactions panel with pointerdown, pointerup, and click events overlays a set of tasks in the main thread panel below. The click interaction starts before the event callbacks that drive the interaction due to a long task that delays the start of the event processing.&quot; decoding=&quot;async&quot; height=&quot;424&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/x0WEjmPG6nnLy3Q2iJW3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Figure 2. An interaction profiled in the performance profiler in Chrome&#39;s DevTools. The interactions track shows a series of events that amount to a click interaction. The interactions track entries span across the tasks responsible for driving the interaction.
  &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; As you attempt to reproduce problems you find in the field in lab tools, you can&#39;t expect that you&#39;ll be able to reproduce the exact conditions in which a high INP was reported. There are many factors that can cause device responses to be slow, and it&#39;s impossible to replicate all of them. However, if certain interactions are consistently slow for many of your users, it should be possible to reproduce those recurring problems by mimicking the conditions common to those users. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;what-if-you-dont-have-field-data&quot;&gt;What if you don&#39;t have field data? &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#what-if-you-dont-have-field-data&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Not everyone collects field data from their website&#39;s users. While your long term performance optimization plans should include collecting field data (as that will make diagnosing issues significantly easier), if you&#39;re not doing that today, it&#39;s still possible to profile your pages and look for interactions that might be slow.&lt;/p&gt;
&lt;p&gt;The first step is to diagnose common user flows. For example, if you&#39;re an online retailer, some common user flows would be to add items to a cart, search for products, and checkout.&lt;/p&gt;
&lt;p&gt;When you test these user flows in the lab, consider doing the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/evaluate-performance/reference/#cpu-throttle&quot; rel=&quot;noopener&quot;&gt;Throttle the CPU&lt;/a&gt; to 4x or 6x speeds to more accurately reflect interaction speeds experienced by users on low-end devices.&lt;/li&gt;
&lt;li&gt;Enable &lt;a href=&quot;https://developer.chrome.com/blog/devtools-mobile/#mobile-emulation&quot; rel=&quot;noopener&quot;&gt;mobile emulation&lt;/a&gt; and choose a low-end mobile device. When you use mobile emulation in DevTools, the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/User-Agent&quot; rel=&quot;noopener&quot;&gt;user agent string&lt;/a&gt; is changed to that of the emulated device, which can affect how page markup is served.&lt;/li&gt;
&lt;li&gt;If you have the ability, consider purchasing a cheaper Android phone (such as a Moto E) with reduced capabilities and profile interactions in the lab using &lt;a href=&quot;https://developer.chrome.com/docs/devtools/remote-debugging/&quot; rel=&quot;noopener&quot;&gt;remote debugging&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you&#39;ve evaluated your potential user flows, make a note of the slowest interactions, and then you can begin to figure out where to start optimizing them. Regardless of whether you&#39;re collecting field data at this point, it depends on what part of the interaction you need to pay attention to in order to know what to optimize.&lt;/p&gt;
&lt;h2 id=&quot;diagnose-and-deal-with-long-input-delay&quot;&gt;Diagnose and deal with long input delay &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#diagnose-and-deal-with-long-input-delay&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;input delay&lt;/em&gt; is the first phase of an interaction. This is the period of time from when the user action is first received by the operating system until the browser is able to start processing the first event triggered by that input. The input delay ends right as the event callbacks for the interaction begin to run.&lt;/p&gt;
&lt;h3 id=&quot;how-to-identify-input-delay&quot;&gt;How to identify input delay &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#how-to-identify-input-delay&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Identifying input delay in Chrome&#39;s performance profiler can be done by finding the start of an interaction in the interactions panel, and then finding the beginning of when the event callbacks for that interaction start to run.&lt;/p&gt;
&lt;p&gt;You&#39;ll always incur at least &lt;em&gt;some&lt;/em&gt; input delay, as it takes some time for the operating system to pass the input event to the browser—but you do have some control over how long the input delay is. &lt;strong&gt;The key is to figure out if there is work running on the main thread that&#39;s preventing your callbacks from running.&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A depiction of input delay in Chrome&amp;#x27;s performance panel. The start of the interaction comes significantly before the event callbacks because of increased input delay due to a timer firing from a third-party script.&quot; decoding=&quot;async&quot; height=&quot;605&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/QtGLNusw9pAe9DJ29Hd6.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Figure 3. Input delay caused by a task fired by a timer from a third-party script.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the previous figure a task from a third-party script is running as the user attempts to interact with the page, and therefore extends the input delay. The extended input delay affects the interaction&#39;s latency, and could therefore affect the page&#39;s INP.&lt;/p&gt;
&lt;h3 id=&quot;how-to-fix-long-input-delays&quot;&gt;How to fix long input delays &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#how-to-fix-long-input-delays&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to solutions for long input delays, it all depends. If you have expensive first-party work that could be affecting an interaction&#39;s input delay, the answer is four-fold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do as little work as possible in any tasks your code kicks off.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-long-tasks/#use-asyncawait-to-create-yield-points&quot;&gt;Break up long tasks&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-long-tasks/#a-dedicated-scheduler-api&quot;&gt;Use the Scheduler API&lt;/a&gt; to prioritize critical tasks and defer non-critical tasks.&lt;/li&gt;
&lt;li&gt;Consider using &lt;a href=&quot;https://web.dev/optimize-long-tasks/#yield-only-when-necessary&quot;&gt;&lt;code&gt;isInputPending&lt;/code&gt;&lt;/a&gt; to check if a user input is pending. If so, &lt;a href=&quot;https://web.dev/optimize-long-tasks/#yield-only-when-necessary&quot;&gt;you can yield to the main thread&lt;/a&gt; so the event callbacks for that input can run sooner than they otherwise would.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If it&#39;s third-party code that&#39;s causing problems, then you have &lt;a href=&quot;https://web.dev/third-party-javascript/&quot;&gt;a lot more to consider&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do a complete inventory of all your website&#39;s third-party scripts.&lt;/li&gt;
&lt;li&gt;Figure out if more than one third-party script&#39;s functionality overlaps significantly with others.&lt;/li&gt;
&lt;li&gt;Cull redundant or low-value third-party scripts.&lt;/li&gt;
&lt;li&gt;Maintain whatever third-party scripts are left over so that they impact performance as little as possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is difficult in large part because third-party JavaScript is an issue of work culture. For example (&lt;a href=&quot;https://web.dev/tag-best-practices/&quot;&gt;tag managers&lt;/a&gt; make it easy for non-technical people in a company to add third-party scripts without the knowledge of the development teams.&lt;/p&gt;
&lt;h2 id=&quot;optimize-event-callbacks&quot;&gt;Optimize event callbacks &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#optimize-event-callbacks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The input delay is only the first part of what INP measures. You&#39;ll also need to make sure that the event callbacks that run in response to a user interaction can complete as quickly as possible.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A depiction of event callback tasks in Chrome&amp;#x27;s performance panel. The event callbacks occur for the pointerdown and click events, which compose a long task.&quot; decoding=&quot;async&quot; height=&quot;605&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/KLel48JOVGvWEKdBrS5I.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Figure 4. The event callbacks that run in response to a tap interaction, as shown in the performance profiler in Chrome DevTools.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The best way to ensure your event callbacks run quickly is to limit what gets run to just the logic that is required to apply visual updates for the next frame. Everything else can be deferred to a subsequent task.&lt;/p&gt;
&lt;p&gt;For example, imagine a rich text editor that formats text as your type but also updates other aspects of the UI in response to what you&#39;ve written (such as word count, spelling mistakes, etc.). In addition, the application may also need to save what you&#39;ve written so that if you leave and return, you haven&#39;t lost any work.&lt;/p&gt;
&lt;p&gt;In this example, the following four things need to happen in response to characters typed by the user. However, only the first item &lt;em&gt;needs&lt;/em&gt; to be done before the next frame is presented.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the text box with what the user typed and apply any required formatting.&lt;/li&gt;
&lt;li&gt;Update the part of the UI that displays the current word count.&lt;/li&gt;
&lt;li&gt;Run logic to check for spelling mistakes.&lt;/li&gt;
&lt;li&gt;Save the most recent changes (either locally or to a remote database).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code to do this might look something like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;textBox&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;keydown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;keyboardEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Update the UI immediately, so the changes the user made&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// are visible as soon as the next frame is presented.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;updateTextBox&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keyboardEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Defer all other work until at least after the next frame,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// by queuing a task in a `requestAnimationFrame()` callback.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; textBox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;updateWordCount&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;checkSpelling&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;saveChanges&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;The following visualization should help explain why deferring any non-critical updates until after the next frame can reduce the processing time and thus the overall interaction latency.&lt;/p&gt;
&lt;figure&gt;
  &lt;a href=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Me4oU1cqMPOqEaEg2XAP.svg&quot; rel=&quot;noopener&quot;&gt;
    &lt;img alt=&quot;A depiction of a keyboard interaction and subsequent tasks in two scenarios. In the top figure, the render-critical task and all subsequent background tasks run synchronously until the opportunity to present a frame has arrived. In the bottom figure, the render-critical work runs first, then yields to the main thread to present a new frame sooner. The background tasks run thereafter.&quot; decoding=&quot;async&quot; height=&quot;495&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 770px) 770px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/MN6LranaUtJMlGZEA66T.png?auto=format&amp;w=1540 1540w&quot; width=&quot;770&quot; /&gt;
  &lt;/a&gt;
  &lt;figcaption&gt;
    Click the above figure to see a high-resolution version.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;While admittedly the use of &lt;code&gt;setTimeout()&lt;/code&gt; inside of a call to &lt;code&gt;requestAnimationFrame()&lt;/code&gt; in the previous code example is a bit esoteric, it is an effective and cross-browser way to ensure that the non-critical code does not block the next frame.&lt;/p&gt;
&lt;p&gt;In the future, as new Scheduling APIs like &lt;a href=&quot;https://web.dev/optimize-long-tasks/#a-dedicated-scheduler-api&quot;&gt;&lt;code&gt;scheduler.postTask()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://web.dev/optimize-long-tasks/#built-in-yield-with-continuation&quot;&gt;&lt;code&gt;scheduler.yield()&lt;/code&gt;&lt;/a&gt; are standardized and implemented, it will be easier for developers to write code that can be automatically prioritized without them needing to have an intimate knowledge of the browser event loop.&lt;/p&gt;
&lt;h2 id=&quot;minimize-presentation-delay&quot;&gt;Minimize presentation delay &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#minimize-presentation-delay&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last step of an interaction is the presentation delay, which starts when the event callbacks have finished running, and ends when the browser is able to present the next frame to the user&#39;s display.&lt;/p&gt;
&lt;p&gt;The unfortunate fact is that presentation delays are something you have the least amount of control over. However, here&#39;s a few things to look out for if you&#39;re noticing that frames are being delayed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Don&#39;t abuse &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;requestAnimationFrame()&lt;/code&gt;&lt;/a&gt; for work not related to rendering. &lt;code&gt;requestAnimationFrame()&lt;/code&gt; callbacks are run during the rendering phase of the event loop, and must complete before the next frame can be presented. If you&#39;re using &lt;code&gt;requestAnimationFrame()&lt;/code&gt; to do work that doesn&#39;t involve changes to the user interface, understand that you could be delaying the next frame.&lt;/li&gt;
&lt;li&gt;Be careful with &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; and your assumptions around how they work. Just because you&#39;re using these features (or Promises in general) doesn&#39;t mean that the work they do won&#39;t block rendering. It&#39;s entirely possible that an &lt;code&gt;async&lt;/code&gt; function—even if it &lt;em&gt;does&lt;/em&gt; break the work in a callback into a separate task—can still block rendering if the browser chooses to run it before the next frame is presented. This is why it&#39;s important to &lt;a href=&quot;https://web.dev/optimize-long-tasks/&quot;&gt;keep all tasks short&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Be careful with &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/ResizeObserver&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ResizeObserver&lt;/code&gt;&lt;/a&gt; observer callbacks. Such callbacks are run prior to rendering, and may delay presentation of the next frame if the work in them is expensive, as with event callbacks, defer any logic not needed for the very next frame.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;when-interactions-overlap&quot;&gt;When interactions overlap &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#when-interactions-overlap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s also important to understand how interactions can overlap. For example, if there are many interactions within a short period, it&#39;s possible that the processing time or presentation delay for one interaction can be a source of input delay for a subsequent interaction.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A depiction of when tasks can overlap to produce long input delays. In this depiction, a click interaction overlaps with a keydown interaction to increase the input delay for the keydown interaction.&quot; decoding=&quot;async&quot; height=&quot;307&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/ohYy7phsKRbKCeth0iUu.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Figure 6. A visualization of two concurrent interactions in the performance profiler in Chrome&#39;s DevTools. The rendering work in the initial click interaction causes an input delay for the subsequent keyboard interaction.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These overlaps are tricky to diagnose in the field, in part because it&#39;s difficult to track if the source of a high INP is due to multiple interactions that interfere with one another. The best thing you can do to alleviate poor responsiveness in your interactions is to &lt;strong&gt;do as little work as possible&lt;/strong&gt; in your interaction&#39;s event callbacks and &lt;strong&gt;always keep your tasks short&lt;/strong&gt;. This helps to reduce contention between interactions and gives the main thread a bit more breathing room.&lt;/p&gt;
&lt;h2 id=&quot;improving-inp-requires-persistence&quot;&gt;Improving INP requires persistence &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/optimize-inp/#improving-inp-requires-persistence&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Improving your site&#39;s INP is an iterative process. When you fix a slow interaction in the field, chances are good that—especially if your website provides tons of interactivity—you&#39;ll start to find other slow interactions, and you&#39;ll need to optimize them too.&lt;/p&gt;
&lt;p&gt;The key to improving INP is persistence. In time, you can get your page&#39;s responsiveness in a spot where users are happy with the experience you&#39;re providing them. Chances are also good that as you develop new features for your users, you may need to go through the same process in optimizing interactions specific to them. It will take time and effort, but it&#39;s time and effort well spent.&lt;/p&gt;
</content>
      <author>
          <name>Jeremy Wagner</name>
        </author><author>
          <name>Philip Walton</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>New to the web platform in November</title>
      <link href="https://web.dev/web-platform-11-2022/"/>
      <updated>2022-11-30T00:00:00Z</updated>
      <id>https://web.dev/web-platform-11-2022/</id>
      <content type="text/html" mode="escaped">&lt;h2 id=&quot;stable-browser-releases&quot;&gt;Stable browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#stable-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In November, &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/107&quot; rel=&quot;noopener&quot;&gt;Firefox 107&lt;/a&gt;, and &lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-108/&quot; rel=&quot;noopener&quot;&gt;Chrome 108&lt;/a&gt; became stable. Let&#39;s take a look at what this means for the web platform.&lt;/p&gt;
&lt;h3 id=&quot;a-change-to-layout-viewport-behavior-in-chrome-on-android&quot;&gt;A change to Layout Viewport behavior in Chrome on Android &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#a-change-to-layout-viewport-behavior-in-chrome-on-android&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There&#39;s a change to how the Layout Viewport behaves from Chrome 108 on Android when the on-screen keyboard is shown. Read &lt;a href=&quot;https://developer.chrome.com/blog/viewport-resize-behavior/&quot; rel=&quot;noopener&quot;&gt;Prepare for viewport resize behavior changes coming to Chrome on Android&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;h3 id=&quot;new-viewport-units&quot;&gt;New viewport units &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#new-viewport-units&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Also in Chrome 108 are the new CSS Viewport Units. These include small (&lt;code&gt;svw&lt;/code&gt;, &lt;code&gt;svh&lt;/code&gt;, &lt;code&gt;svi&lt;/code&gt;, &lt;code&gt;svb&lt;/code&gt;, &lt;code&gt;svmin&lt;/code&gt;, &lt;code&gt;svmax&lt;/code&gt;), large (&lt;code&gt;lvw&lt;/code&gt;, &lt;code&gt;lvh&lt;/code&gt;, &lt;code&gt;lvi&lt;/code&gt;, &lt;code&gt;lvb&lt;/code&gt;, &lt;code&gt;lvmin&lt;/code&gt;, &lt;code&gt;lvmax&lt;/code&gt;), dynamic (&lt;code&gt;dvw&lt;/code&gt;, &lt;code&gt;dvh&lt;/code&gt;, &lt;code&gt;dvi&lt;/code&gt;, &lt;code&gt;dvb&lt;/code&gt;, &lt;code&gt;dvmin&lt;/code&gt;, &lt;code&gt;dvmax&lt;/code&gt;), and logical (&lt;code&gt;vi&lt;/code&gt;, &lt;code&gt;vb&lt;/code&gt;) units. These units are already implemented in Firefox and Safari, meaning that we now have interop across the three main browser engines for these units.&lt;/p&gt;
&lt;p&gt;Read &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/pwa/viewport/-units/&quot; rel=&quot;noopener&quot;&gt;The Large, Small, and Dynamic viewport units&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 101, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        101
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-size&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-size&lt;/code&gt;&lt;/a&gt; shorthand CSS property is supported in Firefox 107, along with the longhand &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-width&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-width&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-height&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-height&lt;/code&gt;&lt;/a&gt; and logical properties &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-block-size&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-block-size&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-inline-size&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-inline-size&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are applied to specify the size of a UI element that is subject to size containment. This allows a user agent to determine the size of an element without needing to render its child elements. They are useful when an element is subject to &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Containment#size_containment&quot; rel=&quot;noopener&quot;&gt;size containment&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 83, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        83
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 107, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        107
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 83, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        83
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;no&quot;&gt;
        ×
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-size#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h3 id=&quot;support-for-the-css-fragmentation-avoid-keyword&quot;&gt;Support for the CSS fragmentation &lt;code&gt;avoid&lt;/code&gt; keyword &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#support-for-the-css-fragmentation-avoid-keyword&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome 108 includes support for the &lt;code&gt;avoid&lt;/code&gt; value of the CSS fragmentation properties &lt;code&gt;break-before&lt;/code&gt;, &lt;code&gt;break-after&lt;/code&gt;, and &lt;code&gt;break-inside&lt;/code&gt; when printing. This value tell the browser to avoid breaking before, after or inside the element it is applied to. For example, the following CSS avoids a figure being broken at a page break.&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;figure&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;break-inside&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; avoid&lt;span 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 addition is due to the inclusion of print support using LayoutNG, this brings a modern, lessy buggy experience. &lt;a href=&quot;https://developer.chrome.com/articles/layoutng/&quot; rel=&quot;noopener&quot;&gt;Learn more about LayoutNG&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;federated-credential-management-api&quot;&gt;Federated Credential Management API &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#federated-credential-management-api&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Federated Credential Management API (FedCM) provides an abstraction for federated identity flows on the web. It exposes a browser mediated dialog that allows users to choose accounts from identify providers to login to websites. FedCM is shipping in Chrome 108, find out more about it in the &lt;a href=&quot;https://developer.chrome.com/blog/fedcm-shipping/&quot; rel=&quot;noopener&quot;&gt;FedCM announcement blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;beta-browser-releases&quot;&gt;Beta browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-11-2022/#beta-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beta browser versions give you a preview of things that will be in the next stable version of the browser. It&#39;s a great time to test new features, or removals, that could impact your site before the world gets that release. Due to where release dates fall, the only new beta this month is &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/108&quot; rel=&quot;noopener&quot;&gt;Firefox 108&lt;/a&gt;, with &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-16_2-release-notes&quot; rel=&quot;noopener&quot;&gt;Safari 16.2 beta&lt;/a&gt; still ongoing.&lt;/p&gt;
&lt;p&gt;Firefox 108 supports &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; attributes for the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/source&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt;&lt;/a&gt; element, when it is a child of a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element. These attributes accept the height or width of the image, in pixels, as an integer without a unit.&lt;/p&gt;
&lt;p&gt;Implementation of container queries is underway in Firefox. Behind the &lt;code&gt;layout.css.container-queries.enabled&lt;/code&gt; flag in Firefox 108 beta, you will find the container query length units—&lt;code&gt;cqw&lt;/code&gt;, &lt;code&gt;cqh&lt;/code&gt;, &lt;code&gt;cqi&lt;/code&gt;, &lt;code&gt;cqb&lt;/code&gt;, &lt;code&gt;cqmin&lt;/code&gt;, &lt;code&gt;cqmax&lt;/code&gt;. These are units of length relative to the size of a query container.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@mattseymour?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Matt Seymour&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Rachel Andrew</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>The large, small, and dynamic viewport units</title>
      <link href="https://web.dev/viewport-units/"/>
      <updated>2022-11-29T00:00:00Z</updated>
      <id>https://web.dev/viewport-units/</id>
      <content type="text/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 browser engines! &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;the-viewport-and-its-units&quot;&gt;The viewport and its units &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/viewport-units/#the-viewport-and-its-units&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To size something as tall as the viewport, you can use the &lt;code&gt;vw&lt;/code&gt; and &lt;code&gt;vh&lt;/code&gt; units.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vw&lt;/code&gt; = 1% of the width of the viewport size.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vh&lt;/code&gt; = 1% of the height of the viewport size.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Give an element a width of &lt;code&gt;100vw&lt;/code&gt; and a height of &lt;code&gt;100vh&lt;/code&gt;, and it will cover the viewport entirely.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A light blue element set to be 100vw by 100vh, covering the entire viewport. The viewport itself is indicated using a blue dashed border.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/IpR2qrX8ENZ1MRMJfehn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;A light blue element set to be 100vw by 100vh, covering the entire viewport.&lt;br /&gt;The viewport itself is indicated using a blue dashed border.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;vw&lt;/code&gt; and &lt;code&gt;vh&lt;/code&gt; units landed in browsers with these additional units&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vi&lt;/code&gt; = 1% of the size of the viewport’s inline axis.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vb&lt;/code&gt; = 1% of the size of the viewport’s block axis.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmin&lt;/code&gt; = the smaller of &lt;code&gt;vw&lt;/code&gt; or &lt;code&gt;vh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmax&lt;/code&gt; = the larger of &lt;code&gt;vw&lt;/code&gt; or &lt;code&gt;vh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These units have good browser support.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 20, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        20
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 19, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        19
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 12, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        12
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 6, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        6
      &lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;the-need-for-new-viewport-units&quot;&gt;The need for new viewport units &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/viewport-units/#the-need-for-new-viewport-units&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the existing units work well on desktop, it’s a different story on mobile devices. There, the viewport size is influenced by the presence or absence of dynamic toolbars. These are user interfaces such as address bars and tab bars.&lt;/p&gt;
&lt;p&gt;Although the viewport size can change, the &lt;code&gt;vw&lt;/code&gt; and &lt;code&gt;vh&lt;/code&gt; sizes do not. As a result, elements sized to be &lt;code&gt;100vh&lt;/code&gt; tall will bleed out of the viewport.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;100vh on mobile is too tall on load.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/bWbl71iEuR5Gu9a2eAxD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;100vh on mobile is too tall on load.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When scrolling down these dynamic toolbars will retract. In this state, elements sized to be &lt;code&gt;100vh&lt;/code&gt; tall will cover the entire viewport.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;100vh on mobile is “correct” when the User-Agent user interfaces are retracted.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/kuGqSsKtDI1PNUDEVx8n.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;100vh on mobile is “correct” when the User-Agent user interfaces are retracted.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To solve this problem, the various states of the viewport have been specified at the CSS Working Group.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Large viewport&lt;/strong&gt;: The viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be retracted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Small Viewport&lt;/strong&gt;: The viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be expanded.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Visualizations of the large and small viewports.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ZwgiN6CI2ERg04ntpnNG.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Visualizations of the large and small viewports.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The new viewports also have units assigned to them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Units representing the large viewport have the &lt;code&gt;lv&lt;/code&gt; prefix. The units are &lt;code&gt;lvw&lt;/code&gt;, &lt;code&gt;lvh&lt;/code&gt;, &lt;code&gt;lvi&lt;/code&gt;, &lt;code&gt;lvb&lt;/code&gt;, &lt;code&gt;lvmin&lt;/code&gt;, and &lt;code&gt;lvmax&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Units representing the small viewport have the &lt;code&gt;sv&lt;/code&gt; prefix. The units are &lt;code&gt;svw&lt;/code&gt;, &lt;code&gt;svh&lt;/code&gt;, &lt;code&gt;svi&lt;/code&gt;, &lt;code&gt;svb&lt;/code&gt;, &lt;code&gt;svmin&lt;/code&gt;, and &lt;code&gt;svmax&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The sizes of these viewport-percentage units are fixed (and therefore stable) unless the viewport itself is resized.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Two mobile browser visualizations positioned next to each other. One has an element sized to be 100svh and the other 100lvh.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/ScGKMyzS1WyS7ByoVvn8.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Two mobile browser visualizations positioned next to each other.&lt;br /&gt;One has an element sized to be 100svh and the other 100lvh.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In addition to the large and small viewports, there‘s also a dynamic viewport which has dynamic consideration of the UA UI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the dynamic toolbars are expanded, the dynamic viewport is equal to the size of the small viewport.&lt;/li&gt;
&lt;li&gt;When the dynamic toolbars are retracted, the dynamic viewport is equal to the size of the large viewport.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Its accompanied units have the &lt;code&gt;dv&lt;/code&gt; prefix: &lt;code&gt;dvw&lt;/code&gt;, &lt;code&gt;dvh&lt;/code&gt;, &lt;code&gt;dvi&lt;/code&gt;, &lt;code&gt;dvb&lt;/code&gt;, &lt;code&gt;dvmin&lt;/code&gt;, and &lt;code&gt;dvmax&lt;/code&gt;. Their sizes are clamped between their &lt;code&gt;lv*&lt;/code&gt; and &lt;code&gt;sv*&lt;/code&gt; counterparts.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;100dvh adapts itself to be either the large or small viewport size.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/AeNB0cHNDkYPUYzDuv8gInYA9rY2/UCWsRe1PmYg7nvAvTu86.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;100dvh adapts itself to be either the large or small viewport size.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These units ship in Chrome 108, joining Safari and Firefox which already have support.&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 101, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        101
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 108, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        108
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&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; In browsers that don’t have dynamic UA UI–such as Chrome on desktop–the size of the large, small, and dynamic viewports are the same. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;caveats&quot;&gt;Caveats &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/viewport-units/#caveats&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There‘s a few caveats to know about Viewport Units:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;None of the viewport units take the size of scrollbars into account. On systems that have classic scrollbars enabled, an element sized to &lt;code&gt;100vw&lt;/code&gt; will therefore be a little bit too wide. This is as &lt;a href=&quot;https://www.w3.org/TR/css-values-4/#viewport-relative-lengths:~:text=In%20all%20cases%2C%20scrollbars%20are%20assumed%20not%20to%20exist.&quot; rel=&quot;noopener&quot;&gt;per specification&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The values for the dynamic viewport do not update at 60fps. In all browsers updating is throttled as the UA UI expands or retracts. Some browsers even debounce updating entirely depending on the gesture (a slow scroll versus a swipe) used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The on-screen keyboard (also known as the virtual keyboard) is not considered part of the UA UI. Therefore it does not affect the size of the viewport units. In Chrome &lt;a href=&quot;https://developer.chrome.com/blog/viewport-resize-behavior/#opting-in-to-a-different-behavior&quot; rel=&quot;noopener&quot;&gt;you can opt-in to a behavior where the presence of the virtual keyboard does affect the viewport units&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/viewport-units/#additional-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To learn more about viewports and these units check out &lt;a href=&quot;https://www.youtube.com/watch?v=xl9R8aTOW_I&quot; rel=&quot;noopener&quot;&gt;this episode of HTTP 203&lt;/a&gt;. In it, &lt;a href=&quot;https://web.dev/authors/bramus/&quot;&gt;Bramus&lt;/a&gt; tells &lt;a href=&quot;https://web.dev/authors/jakearchibald/&quot;&gt;Jake&lt;/a&gt; all about the various viewports and explains how exactly the sizes of these units are determined.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;xl9R8aTOW_I&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;Additional reading material:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-values-4/#viewport-relative-lengths&quot; rel=&quot;noopener&quot;&gt;CSS Values 4 Specification: Viewport-relative lengths&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chromestatus.com/feature/5170718078140416?context=myfeatures&quot; rel=&quot;noopener&quot;&gt;ChromeStatus Entry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/web-platform-tests/interop-2022-viewport/blob/main/explainers/layout-viewport.md&quot; rel=&quot;noopener&quot;&gt;Layout Viewport explainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/web-platform-tests/interop-2022-viewport/blob/main/explainers/viewport-units.md&quot; rel=&quot;noopener&quot;&gt;Viewport Units explainer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Bramus</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Accessibility Week</title>
      <link href="https://web.dev/accessibility-week-2022/"/>
      <updated>2022-11-18T00:00:00Z</updated>
      <id>https://web.dev/accessibility-week-2022/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;This week we highlighted accessibility resources to help you make your sites
and applications usable by everyone.&lt;/p&gt;
&lt;p&gt;We&#39;re continuing to roll out &lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility&lt;/a&gt;, a
brand new course written by &lt;a href=&quot;https://twitter.com/cariefisher&quot; rel=&quot;noopener&quot;&gt;Carie Fisher&lt;/a&gt;
that will take you through the essentials for building accessible websites and
web apps.&lt;/p&gt;
&lt;p&gt;We&#39;ve had 3 community spotlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-melanie/&quot;&gt;Melanie Sumner&lt;/a&gt; told us about her journey
into engineering, accessible design, Ember.js, and the importance of funding
these efforts.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-shuyi/&quot;&gt;Olutimilehin Olushuyi&lt;/a&gt; told us about his move
from the law to web development, building accessible community, and creating
accessible layouts.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/community-highlight-albert-kim/&quot;&gt;Albert Kim&lt;/a&gt; told us about mental health
awareness, building for invisible disabilities, the  COGA Accessibility
Community Group, and more practical wisdom.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;watch-us-answer-your-questions&quot;&gt;Watch us answer your questions &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/accessibility-week-2022/#watch-us-answer-your-questions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On Thursday, Alexandra White spoke with Carie Fisher and Melanie Sumner about
accessibility, and we answered some of your questions.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;xvGDgDRWl_E&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;Have more questions? Ask us on Twitter,
&lt;a href=&quot;https://twitter.com/chromiumdev&quot; rel=&quot;noopener&quot;&gt;@ChromiumDev&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-resources&quot;&gt;More resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/accessibility-week-2022/#more-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A solid document structure is a great start for accessible development. Find
out how to really use HTML in  our &lt;a href=&quot;https://web.dev/learn/html&quot;&gt;Learn HTML&lt;/a&gt; course. Follow it
up with Learn Accessibility&#39;s &lt;a href=&quot;https://web.dev/learn/accessibility/structure/&quot;&gt;Content structure module&lt;/a&gt;
for more on semantic HTML, landmarks, and tables for accessible content.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://web.dev/testing-web-design-color-contrast/&quot;&gt;Testing web design color contrast&lt;/a&gt; get
an overview of three tools and techniques to ensure your content is readable by
everyone.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://web.dev/website-navigation/&quot;&gt;Building the main navigation for a website&lt;/a&gt; learn how to create accessible navigation using semantic HTML.&lt;/p&gt;
&lt;h2 id=&quot;on-the-web&quot;&gt;On the web &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/accessibility-week-2022/#on-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The W3C hosts a collection of &lt;a href=&quot;https://www.w3.org/WAI/courses/list/&quot; rel=&quot;noopener&quot;&gt;courses, training, and certification on digital accessibility&lt;/a&gt; from different providers.&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&quot;https://www.smashingmagazine.com/category/accessibility/&quot; rel=&quot;noopener&quot;&gt;Accessibility articles on Smashing Magazine&lt;/a&gt;, including &lt;a href=&quot;https://www.smashingmagazine.com/2022/07/article-section-elements-accessibility/&quot; rel=&quot;noopener&quot;&gt;&amp;lt;article&amp;gt; vs. &amp;lt;section&amp;gt;: How To Choose The Right One&lt;/a&gt; by Olushuyi Olutimilehin.&lt;/li&gt;
&lt;li&gt;If you&#39;re making a case for accessibility work at your company, check out Melanie Sumner&#39;s &lt;a href=&quot;https://pleasefunda11y.com/&quot; rel=&quot;noopener&quot;&gt;pleasefunda11y.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you want to support the Cognitive and Learning Disabilities Accessibility Task Force, join the &lt;a href=&quot;https://www.w3.org/community/coga-community/&quot; rel=&quot;noopener&quot;&gt;COGA Accessibility Community Group&lt;/a&gt;. This group supplies user needs and feedback to the COGA Task Force.&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author><author>
          <name>Rachel Andrew</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Community highlight: Albert Kim</title>
      <link href="https://web.dev/community-highlight-albert-kim/"/>
      <updated>2022-11-17T00:00:00Z</updated>
      <id>https://web.dev/community-highlight-albert-kim/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;em&gt;This post highlights a community expert, as a part of &lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra White&lt;/strong&gt;: How would you introduce yourself? You do so much accessibility work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert Kim&lt;/strong&gt;: I&#39;m a digital accessibility subject matter expert (SME), a UX
design consultant, and a public speaker and coach, raising mental health
awareness in the tech community.&lt;/p&gt;
&lt;figure data-float=&quot;right&quot;&gt;
  &lt;img alt=&quot;Albert Kim is an accessibility SME.&quot; decoding=&quot;async&quot; height=&quot;314&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 350px) 350px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/oXT7rUXWYTEXaDfIabUf.jpg?auto=format&amp;w=700 700w&quot; width=&quot;350&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I founded &lt;a href=&quot;https://twitter.com/a11ynextgen&quot; rel=&quot;noopener&quot;&gt;Accessibility NextGen&lt;/a&gt;, a community
for people interested in learning more about accessibility. I&#39;m a
&lt;a href=&quot;https://disabilityin.org/what-we-do/nextgen-leaders-initiatives/&quot; rel=&quot;noopener&quot;&gt;Disability:IN NextGen Leader&lt;/a&gt;.
And currently, I&#39;m a W3C invited expert for the
&lt;a href=&quot;https://www.w3.org/WAI/GL/task-forces/coga/&quot; rel=&quot;noopener&quot;&gt;Cognitive and Learning Disabilities Task Force&lt;/a&gt;
and Mental Health Sub-Group. Lately, I&#39;ve been researching how to include
people with OCD, ADHD, dyslexia, and PTSD into the product development
process.&lt;/p&gt;
&lt;p&gt;Offline, I&#39;m a DEI community leader, blogger, huge foodie, photographer, and I
love traveling—I travel a lot. I&#39;m the first generation in my family to live
abroad, the first generation to get any formal education. I was raised by a
single mother in a low-income household. I&#39;m a military veteran.&lt;/p&gt;
&lt;p&gt;I identify myself as someone who can empathize with a lot of different
struggles and life stories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Did you always think you&#39;d be someone who would have a career or
work in accessibility?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: I always wanted my profession to be not just a job, but one with
social impact. I&#39;ve switched careers several times. In college, I tried
different majors. I&#39;ve founded startups, I was a business development manager,
I worked in telecommunications in the military. I was an interpreter. I&#39;ve had
many different jobs.&lt;/p&gt;
&lt;p&gt;It&#39;s important to mention all of these different experiences, as all of the
dots began to connect in their own way. I eventually got into digital
accessibility because of my personal experience as someone with a disability,
but also with a love for digital products. I really, really love a good
product. Useful, functional products.&lt;/p&gt;
&lt;p&gt;We often use the phrase &amp;quot;&lt;a href=&quot;https://web.dev/learn/accessibility/glossary/#at&quot;&gt;assistive technology&lt;/a&gt;,&amp;quot;
but all technologies are assistive. I&#39;m passionate about digital products that
help improve my life, that make my life easier. I want to connect consumers
with the producers of digital products, and digital accessibility is
fundamental to that connection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Can you expand more on how you create opportunities for direct
communication between users and product creators?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: Often, when developers build digital products, they don&#39;t make full
use of their own product. They aren&#39;t aware of how useful their product
is for users, especially those with disabilities. That means that they&#39;re not
thinking about those use cases in the design process. Because of this, they
often miss an opportunity to discover disabled users who could become loyal
customers.&lt;/p&gt;
&lt;p&gt;Designers and developers may or may not find out later that what they built is
useful to disabled users.&lt;/p&gt;
&lt;p&gt;Connecting product owners and developers to their users with disabilities
early in the product development process can lead to full realization of
a product&#39;s potential. This is in addition to products designed with accessibility as an intentional feature.&lt;/p&gt;
&lt;p&gt;As a metaphor, I love sharing good food with my loved ones. The joy is doubled
when I can share it. Just like that, I want to share really good products with
my friends, but I cannot always share them if they&#39;re not accessible. A blog
post alone, without a screen reader or other interventions, is not accessible
to my blind friend. If digital product makers hear these stories from users,
then hopefully they&#39;ll make accessible design choices so the users can fully
utilize their products.&lt;/p&gt;
&lt;h2 id=&quot;build-for-invisible-disabilities&quot;&gt;Build for &amp;quot;invisible&amp;quot; disabilities &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-albert-kim/#build-for-invisible-disabilities&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I appreciate that you mentioned your blind friend specifically,
because often the first thing that comes to mind when developers and designers
&lt;em&gt;do&lt;/em&gt; think about disability are the &amp;quot;obvious&amp;quot; ones: visible and often permanent
disabilities. But there are &lt;a href=&quot;https://web.dev/learn/accessibility/why/#additional-beneficiaries-of-accessibility&quot;&gt;so many people impacted by accessible
design&lt;/a&gt;,
such as those with temporary and invisible disabilities, like psychological
disabilities.&lt;/p&gt;
&lt;p&gt;You&#39;re an invited expert to the W3C group, ​​the
&lt;a href=&quot;https://www.w3.org/WAI/GL/task-forces/coga/&quot; rel=&quot;noopener&quot;&gt;Cognitive and Learning Disabilities Task Force&lt;/a&gt;
and Mental Health subgroup. What is COGA?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: The COGA task force is a joint commitment of the Accessible
Platform Architecture (APA) Working Group and the Web Content Accessibility
Guidelines (WCAG) Working Group. COGA assists these other groups in creating
guidance documents, as well as updates to existing W3C accessibility
guidelines. For example, we further developed proposed success criteria for WCAG 2.1.&lt;/p&gt;
&lt;p&gt;We&#39;ve built a repository of &lt;a href=&quot;https://w3c.github.io/coga/user-research/&quot; rel=&quot;noopener&quot;&gt;user research&lt;/a&gt;
to serve as supplemental guidance and have published
&lt;a href=&quot;https://w3c.github.io/coga/issue-papers/&quot; rel=&quot;noopener&quot;&gt;issue papers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Often, companies and developers look at WCAG guidelines as their standard for
web accessibility. But, there&#39;s supplemental guidance in the form of issue
papers. COGA has written some of these papers on different use cases to help
describe cognitive disabilities and scenarios where persons with atypical
profiles use technology successfully and unsuccessfully. We help these working
groups think about cognitive disabilities and learning disabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Have you been with COGA from the start?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: I joined a few years after the group was developed; but after I
joined, I strongly advocated for a mental health subgroup. COGA&#39;s focus was
primarily on cognitive and learning disabilities, but I wanted to start a
conversation about mental health.&lt;/p&gt;
&lt;p&gt;I happened to know someone in that community who reached out on Twitter.
I got in through that connections, and I&#39;m very passionate about bringing
invisible disabilities into web accessibility spaces.&lt;/p&gt;
&lt;h2 id=&quot;participate-in-coga-and-other-w3c-initiatives&quot;&gt;Participate in COGA and other W3C initiatives &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-albert-kim/#participate-in-coga-and-other-w3c-initiatives&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Can anyone participate in such a group, and do people attend
regularly?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: It&#39;s an open group! &lt;a href=&quot;https://www.w3.org/WAI/GL/task-forces/coga/#participation&quot; rel=&quot;noopener&quot;&gt;Anyone can join&lt;/a&gt;,
as participants of either the APA Working Group or the WCAG Working Group. If
your company sponsors the W3C, you can join, or as an independent invited
expert. I&#39;m an independent invited expert.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: For most of my career, I didn&#39;t know that. I didn&#39;t realize how
much power an individual could have in influencing and even creating standards
that make up the web.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: It&#39;s definitely a big time commitment and a lot of
responsibilities. For some, that may not be feasible.&lt;/p&gt;
&lt;p&gt;The easiest way to participate is to join the
&lt;a href=&quot;https://www.w3.org/community/coga-community/&quot; rel=&quot;noopener&quot;&gt;COGA Accessibility Community Group&lt;/a&gt;.
The community groups are more flexible and don&#39;t have as much responsibility or
commitments. This group supplies user needs and feedback to the COGA Task Force.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Here&#39;s where I confess my own stakes in this work, in your
subgroup. I suffer from anxiety and depression, and have for most of my life.
There are times I&#39;m overwhelmed by certain sites and apps, even those which are
meant to help us be &amp;quot;productive,&amp;quot; as some tasks have long checklist steps
before you can move to the next task. Tools which are helpful on my best days
can be overwhelming the next day.&lt;/p&gt;
&lt;p&gt;In your &lt;a href=&quot;https://a11yrules.com/podcast/albert-kim-talks-about-ocd-ptsd-and-web-accessibility/&quot; rel=&quot;noopener&quot;&gt;Accessibility Rules interview&lt;/a&gt;,
you mentioned the ways in which endless scroll can be traumatic, and how that
affects you as a person with OCD and PTSD. Is there guidance out there or sites
that are doing a good job of giving people a way to opt-out of an experience
that may be triggering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: There is a &lt;a href=&quot;https://www.w3.org/TR/coga-usable/#make-the-relationship-clear-between-controls-and-the-content-they-affect-pattern&quot; rel=&quot;noopener&quot;&gt;COGA issue paper&lt;/a&gt;,
that has supplemental guidance. As far as websites or
resources acting as a good example… that might be hard to find! Addressing
mental health in web development is still very new. But I do have a lot of
advice and specific best practices that I can recommend as a user with
disabilities and as an accessibility SME.&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 &lt;a href=&quot;https://www.w3.org/TR/coga-usable/#make-the-relationship-clear-between-controls-and-the-content-they-affect-pattern&quot;&gt;COGA issue paper&lt;/a&gt; doesn&#39;t directly consult on endless scroll. This advice comes from both Albert&#39;s experience as a neurodivergent user and common best practices. Preventing endless scroll is a widely accepted and understood as an accessibility best practice.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;First thing, follow the WCAG guidelines, though most of them were written prior
to the mental health subgroup existing, so much of that guidance is helpful
beyond those with physical disabilities. It&#39;s helpful for users with invisible
disabilities and mental health disabilities. Following this, that has to be the
beginning. If websites were following these guidelines and did a really good
job, even if they didn&#39;t think about mental health at all, we probably wouldn&#39;t
experience many of these problems.&lt;/p&gt;
&lt;p&gt;One of the most important design choices that would be helpful is clear,
semantic structure. Clear headings can be very helpful for users with OCD,
ADHD, or dyslexia. Even for me, and my anxiety as well. All of these illnesses
share some pain points, they&#39;re interconnected.&lt;/p&gt;
&lt;h2 id=&quot;stop-creating-bad-user-experiences&quot;&gt;Stop creating bad user experiences &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-albert-kim/#stop-creating-bad-user-experiences&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Okay, what about the opposite? What are people building that is
against WCAG recommendations that is causing problems for those with mental
health issues?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: So many things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complex navigation and page layouts that are difficult to navigate and use.&lt;/li&gt;
&lt;li&gt;Multi-stage forms that have a lot of imposed requirements, rather than
communicating with users why something is important or needed.&lt;/li&gt;
&lt;li&gt;Long passages of complex text with a lot of jargon or metaphors that are
difficult to understand, which require additional context.&lt;/li&gt;
&lt;li&gt;Flickering content or background images that are moving or blinking.
Notifications that you can&#39;t turn off easily.&lt;/li&gt;
&lt;li&gt;Timeouts on complex activities, especially without options to save, such as
when you&#39;re filling out a form and you&#39;re given a warning or a timeout after
30 seconds.&lt;/li&gt;
&lt;li&gt;Search on websites that doesn&#39;t work well. This may mean there&#39;s a lack of
filters, and that leads to an endless set of results.&lt;/li&gt;
&lt;li&gt;Unexpected behavior, like when you click a button and the page jumps back to
the top so you have to figure out where you were and scroll back down.&lt;/li&gt;
&lt;li&gt;Hidden actions, like when a cookie popup requires multiple steps in really
small print to decline the cookies. Or deliberately making subscriptions that
are really hard to cancel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These aren&#39;t just accessibility issues, these are usability issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Good product design is accessible design.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;:  There are so many examples. Make a good product and users will
come back. These are just some examples.&lt;/p&gt;
&lt;h2 id=&quot;include-content-warnings&quot;&gt;Include content warnings &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-albert-kim/#include-content-warnings&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Something often politicized, at least in the United States, is
the idea of content warnings (colloquially known as &amp;quot;trigger warnings&amp;quot;).&lt;/p&gt;
&lt;p&gt;These warnings may be related to a design choice—flashing images may cause seizures. Those are less controversial, and fairly commonplace. However, content
warnings for certain subjects is also critical for many.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: If your content has something sensitive, such as violence or
mentions of sexual assault, having warnings can be very helpful for users with
PTSD, depression, and anxiety, especially as it may stem from personal
experience of traumatic events. Allow for customization and personalization
that is obvious, so people can choose what information they are ready to read,
see, or hear.&lt;/p&gt;
&lt;p&gt;The core meaning of the web is to relay information. Rather than imposing our
information, we should be communicating it. We should think about how others
will perceive what we have to share. I may write something one way, but it may
be interpreted by someone else in a different way. Clear structure helps to
avoid some of these miscommunications.&lt;/p&gt;
&lt;p&gt;Summaries and tables of content are also very helpful in allowing a user to
prepare themselves for what they&#39;ll be learning.&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;  If you include a content warning in a video, it&#39;s critical to let this warning play for long enough that people can read the message, especially in contexts where the video may not be paused.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I&#39;m personally grateful for these content trigger warnings, so I
can decide if I&#39;m in a place where I feel comfortable reading or seeing content
which may lead to an emotional reaction. For those who are worried that there
may be pushback on including trigger warnings in their content, do you have any
advice?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: We must think of it as a public health issue, not a political
issue. Trigger warnings are not about censorship, at all. It&#39;s about giving
users freedom to choose. When we don&#39;t provide the option, then we don&#39;t give
users freedom to protect themselves from something that may cause harm to their
mental health.&lt;/p&gt;
&lt;p&gt;We shouldn&#39;t arbitrarily impose or force information on users. The most common
reaction for people with PTSD who encounter trigger content is to leave and
never come back. You lose those people. It&#39;s a health issue.&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;  If you get pushback on adding space for trigger warnings, you could argue it&#39;s a business issue. When you lose those users forever, you lose that revenue or potential revenue.  Learn more about the &lt;a href=&quot;https://web.dev/learn/accessibility/why/#business-impact&quot;&gt;business impact of accessibility&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: There&#39;s some similarity between a trigger warning and a parental
control. We don&#39;t have any political concerns about letting parents choose what
is acceptable to be seen by their children. It&#39;s very conventionally
understood. This is exactly the same. People deserve to have control for
themselves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Seems reasonable to me!&lt;/p&gt;
&lt;h2 id=&quot;do-one-more-thing-communicate-clearly&quot;&gt;Do one more thing: communicate clearly &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-albert-kim/#do-one-more-thing-communicate-clearly&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: If you asked developers to change one thing about the way they
design and build websites to make them more accessible, what would you ask for?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Albert&lt;/strong&gt;: Don&#39;t forget that the fundamental purpose of a website is to
clearly communicate information to the user. To do this, you must think about
what information you want to share with your users, and more importantly, how
to frame that information so the content and your intentions are understood.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Take the Learn Accessibility module on &lt;a href=&quot;https://web.dev/learn/accessibility/structure&quot;&gt;Content structure&lt;/a&gt; to read about semantic HTML, landmarks, data tables, and more. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;You can succeed by building each page with semantic HTML, use a clear
structure and layout of content. Clear structure and layouts help you
communicate better with your users, and are more scalable, usable, and
accessible. Ensure labels are consistent and instructions are provided
correctly. This helps users more easily find the information they seek and
better understand the relationships between different parts of the content.&lt;/p&gt;
&lt;p&gt;This advice touches upon three WCAG success criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-descriptive.html&quot; rel=&quot;noopener&quot;&gt;2.4.6. Headings and Labels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/UNDERSTANDING-WCAG20/content-structure-separation-programmatic.html&quot; rel=&quot;noopener&quot;&gt;1.3.1. Info and Relationships&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/UNDERSTANDING-WCAG20/minimize-error-cues.html&quot; rel=&quot;noopener&quot;&gt;3.3.2. Labels or Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Missing these success criteria is among the most common accessibility issues
found on websites. This affects people who use assistive technologies (such as
screen readers), but also neurodivergent people who may have cognitive and/or
learning disabilities or mental health conditions.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Keep up with Albert&#39;s work on Twitter as
&lt;a href=&quot;https://twitter.com/djkalbert&quot; rel=&quot;noopener&quot;&gt;@djkalbert&lt;/a&gt;. Check out
&lt;a href=&quot;https://www.meetup.com/a11ynextgen/&quot; rel=&quot;noopener&quot;&gt;Accessibility NextGen&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>GDE community highlight: Lars Knudsen</title>
      <link href="https://web.dev/gde-focus-lars-knudsen/"/>
      <updated>2022-11-09T00:00:00Z</updated>
      <id>https://web.dev/gde-focus-lars-knudsen/</id>
      <content type="text/html" mode="escaped">&lt;figure&gt;
&lt;img alt=&quot;Lars presenting on stage with two other speakers.&quot; decoding=&quot;async&quot; height=&quot;600&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/roVI1kelp323efzmIs7X.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Monika:&lt;/strong&gt; What inspired you to become a developer? What’s your current professional focus?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; I got my MSc in engineering, but in fact my interest in tech started much earlier. When I was a kid in the 80s, my father owned a computing company working with graphic design. Sometimes, especially during the summer holidays, he would take me to work with him. At times, some of his employees would keep an eye on me. There was this really smart guy who once said to me, “Lars, I need to get some work done, but here&#39;s a C manual, and there’s a computer over there. Here’s how you start a C compiler. If you have any questions, come and ask me.” I started to write short texts that were translated into something the computer could understand. It seemed magical to me. I was 11 years old when I started and around seventh grade, I was able to create small applications for my classmates or to be used at school. That’s how it started.&lt;/p&gt;
&lt;p&gt;Over the years, I’ve worked for many companies, including Nokia,  Maersk, and Openwave. At the beginning, like in many other professions, because you know a little, you feel like you can do everything, but with time you learn each company has a certain way of doing things.&lt;/p&gt;
&lt;p&gt;After a few years of working for a medical company, I started my own business in 1999. I worked as a freelance contractor and, thanks to that, had the chance to get to know multiple organizations quickly. After completing the first five contracts, I found out that every company thinks they’ve found the perfect setup, but all of them are completely different. At that time, I was also exposed to a lot of different technologies, operating systems etc. Around my early twenties, my mindset changed. At the beginning, I was strictly focused on one technology and wanted to learn all about it. With time, I started to think about combining technologies as a way of improving our lives. I have a particular interest in narrowing the gap between what we call the A and the B team in the world. I try to transfer as much knowledge as possible to regions where people don’t have the luxury of owning a computer or studying at university free of charge.&lt;/p&gt;
&lt;p&gt;I continue to work as a contractor for external partners but, whenever possible, I try to choose projects that have some kind of positive impact on the environment or society. I’m currently working on embedded software for a hearing-aid company called &lt;a href=&quot;https://www.oticon.com/&quot; rel=&quot;noopener&quot;&gt;Oticon&lt;/a&gt;. Software-wise, I’ve been working on everything from the tiniest microcontrollers to the cloud; a lot of what I do revolves around the web. I’m trying to combine technologies whenever it makes sense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monika&lt;/strong&gt;: Were you involved in developer communities before joining the Google Developer Experts program?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; Yes, I was engaged in meetups and conferences. I first connected with the community while working for Nokia. Around 2010, I met &lt;a href=&quot;https://twitter.com/kennethrohde?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor&quot; rel=&quot;noopener&quot;&gt;Kenneth Rohde Christiansen&lt;/a&gt;, who became a GDE before me. He inspired me to see how web technologies can be useful for aspiring tech professionals in developing countries. Developing and deploying solutions using C++, C# or Java requires some years of experience, but everyone who has access to a computer, browser, and notepad can start developing  web-based applications and learn really fast. It’s possible to build a fully functional application with limited resources, and ramp up from nothing. That’s why I call the web a very democratizing technology stack.&lt;/p&gt;
&lt;p&gt;But back to the community—after a while I got interested in web standardization and what problems bleeding edge web technologies could solve. I experimented with new capabilities in a browser before release. I was working for Nokia at the time, developing for a Linux-based flagship device, the N9. The browser we built was WebKit based and I got some great experience developing features for a large open source project. In the years after leaving Nokia, I got involved in web conferences and meetups, so it made sense to join the GDE community in 2017.&lt;/p&gt;
&lt;p&gt;I really enjoy the community work and everything we’re doing together, especially the pre-pandemic Chrome Developer Summits, where I got to help with booth duty alongside a bunch of awesome Google Engineers and other GDEs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monika:&lt;/strong&gt; What advice would you give to a young developer who’s just starting their professional career and is not sure which path to take?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars&lt;/strong&gt;: I’d say from my own experience—if you can afford it—consider freelancing for a couple of different companies. This way, you’ll be exposed to code in many different forms and stages of development. You’ll get to know a multitude of operating systems and languages, and learn how to resolve problems in many ways. This helped me a lotI gained experience as senior developer in my twenties. This approach will help you achieve your professional goals faster.&lt;/p&gt;
&lt;p&gt;Besides that, have fun, explore, play with the hardware and software. Consider building something that solves a real problem—maybe for your friends, family, or a local business. Don’t be afraid to jump into something you’ve never done before.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monika:&lt;/strong&gt; What does the future hold for web technologies?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; I think that for a couple of years now the web has been fully capable of providing a platform for large field applications, both for the consumer and for business. On the server side of things, web technologies offer a seamless experience, especially for frontend developers who want to build a backend component. It’s easier for them to get started now. I know people who were using both Firebase and Heroku to get the job done. And this trend will grow—web technologies will be enough to build complex solutions of any kind. I believe that the &lt;a href=&quot;https://www.chromium.org/teams/web-capabilities-fugu/&quot; rel=&quot;noopener&quot;&gt;Web Capabilities - Project Fugu 🐡&lt;/a&gt; really unlocks that potential.&lt;/p&gt;
&lt;p&gt;Looking at it from a slightly different point of view, I also think that if we provide full documentation and in-depth articles not only in English but also in other languages (for example, Spanish and Portuguese), we would unlock a lot of potential in Latin America—and other regions, of course. Developers there often don’t know English well enough to fully understand all the relevant articles. We should also give them the opportunity to learn as early as possible, even before they start university, while still in their hometowns. They may use those skills to help local communities and businesses before they leave home and maybe never come back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; You came a long way from doing C development on a random computer to hacking on hardware. How did you do that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; I started taking apart a lot of hardware I had at home. My dad was not always happy when I couldn’t put it back together. With time, I learned how to build some small devices, but it really took off much later, around the time I joined Nokia, where I got my embedded experience. I had the chance to build small screensavers, components for the Series 30 phones. I was really passionate about it and could really think outside the box. They assigned me a task to build a Snake game for those devices. It was a very interesting experience. The main difference between building embedded systems and most other things (including web) is that you leave a small footprint—you don’t have much space or memory to use. While building Snake, the RAM that I had available was less than one-third of the frame buffer (around 120 x 120 pixels). I had to come up with ways to algorithmically rejoin components on screen so they’d look static, as if they were tiles. I learned a lot—that was the move from larger systems to small, embedded solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; The skill set of a typical frontend developer is very different from the skill set of someone who builds embedded hardware. How would you encourage a frontend developer to look into hardware and to start thinking in binary?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; I think that the first step is to look at some of the &lt;a href=&quot;https://fugu-tracker.web.app/&quot; rel=&quot;noopener&quot;&gt;Fugu APIs&lt;/a&gt; that work in Chrome and Edge, and are built into all the major systems today. That’s all you need at the start.&lt;/p&gt;
&lt;p&gt;Another thing is that the toolchains for building embedded solutions have a steep learning curve. If you want to build your own custom hardware, start with &lt;a href=&quot;https://www.arduino.cc/&quot; rel=&quot;noopener&quot;&gt;Arduino&lt;/a&gt; or &lt;a href=&quot;http://esp32.net/&quot; rel=&quot;noopener&quot;&gt;ESP32&lt;/a&gt;—something that is easy to buy and fairly cheap. With the right development environment, you can get your project up and running in no time.&lt;/p&gt;
&lt;p&gt;You could also buy a heart rate monitor or a multisensor unit, which are already using Bluetooth GATT services, so you don’t have to build your own hardware or firmware—you can use what’s already there and start experimenting with the Web Bluetooth API to start communicating with it.&lt;/p&gt;
&lt;p&gt;There are also devices that use a serial protocol—for these, you can use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Web_Serial_API&quot; rel=&quot;noopener&quot;&gt;Web Serial API&lt;/a&gt; (&lt;a href=&quot;https://fugu-tracker.web.app/&quot; rel=&quot;noopener&quot;&gt;also Fugu&lt;/a&gt;). Recently I’ve been looking into using the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/WebHID_API&quot; rel=&quot;noopener&quot;&gt;WebHID API&lt;/a&gt;, which enables you to talk to all the human interface devices that everyone has access to. I found some old ones in my basement that had not been supported by any operating system for years, but thanks to reverse engineering it took me a few hours to re-enable them.&lt;/p&gt;
&lt;p&gt;There are different approaches depending on what you want to build, but to a web developer I would say, get a solid sensor unit, maybe a Thingy 52 from Nordic Semiconductor; it has a lot of sensors, and you can hook up to your web application with very little effort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; Connecting to the device is the first step, but then speaking to it effectively—that’s a whole other thing. How come you did not give up after facing obstacles? What kept you motivated to continue working?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; For me personally the social aspect of solving a problem was the most important. When I started working on my own embedded projects, I had a vision and a desire to build a science lab in a box for developing regions. My wife is from Mexico and I saw some of the schools there; some that are located outside of the big cities are pretty shabby, without access to the materials and equipment that we have in our part of the world.&lt;/p&gt;
&lt;p&gt;The passion for building something that can potentially be used to help others—that’s what kept me going. I also really enjoyed the community support. I reached out to some people at Google and all were extremely helpful and patiently answered all of my questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; A lot of people have some sort of hardware at home, but don’t know what to do with it. How do you find inspiration for all your amazing projects, in particular the one under the working name &lt;a href=&quot;https://dev.to/denladeside/zephyr-web-bluetooth-and-accessibility-4ddm&quot; rel=&quot;noopener&quot;&gt;SimpleMouse&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; Well, recently I have been in fact reviving a lot of old hardware, but for this particular project—the name has not been set yet, but let’s call it SimpleMouse—I used my experience. I worked with some accessibility solutions earlier and I saw how some of them just don’t work anymore; you’d need to have an old Windows XP with certain software installed to run them. You can’t really update those, you can only use those at home because you can’t move your setup.&lt;/p&gt;
&lt;p&gt;Because of that, I wondered how to combine my skills from the embedded world with project Fugu and what is now possible on the web to create cheap, affordable hardware combined with easy-to-understand software on both sides, so people can build on that.&lt;/p&gt;
&lt;p&gt;For that particular project, I took a small USB dongle with a reflexive chip, the nRF52840. It communicates with Bluetooth on one side and USB on the other. You can basically program it to be anything on both sides. And then I thought about the devices that control a computer—a mouse and a keyboard. Some people with disabilities may find it difficult to operate those devices, and I wanted to help them.&lt;/p&gt;
&lt;p&gt;The first thing I did was to make sure that any operating system would see the USB dongle as a mouse. You can control it from a native application or a web application—directly into Bluetooth. After that, I built a web application—a simple template that people can extend the way they want using web components. Thanks to that, everyone can control their computer with a web app that I made in just a couple of hours on an Android phone.&lt;/p&gt;
&lt;p&gt;Having that set up will enable anyone in the world with some web experience to build, in a matter of days, a very customized solution for anyone with a disability who wants to control their computer. The cool thing is that you can take it with you anywhere you go and use it with other devices as well. It will be the exact same experience. To me, the portability and affordability of the device are very important because people are no longer confined to using their own devices, and are no longer limited to one location.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; Did you have a chance to test the device in real life?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; Actually during my last trip to Mexico I discussed it with a web professional living there; he’s now looking into the possibilities of using the device locally. Over there the equipment is really expensive, but a USB dongle normally costs around ten US dollars. He’s now checking if we could build local setups there to try it out. But I haven’t done official trials yet here in Denmark.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; Many devices designed to assist people with disabilities are really expensive. Are you planning on cooperating with any particular company and putting it into production for a fraction of the price of that expensive equipment?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; Yes, definitely! I’ve already been talking to a local hardware manufacturer about that. Of course, the device won’t replace all those highly specialized solutions, but it can be the first step to building something bigger—for example, using voice recognition, already available for web technologies. It’ll be an easy way of controlling devices using your Android phone; it can work with a device of any kind.&lt;/p&gt;
&lt;p&gt;Just being able to build whatever you want on the web and to use that to control any host computer opens up a lot of possibilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thomas:&lt;/strong&gt; Are you releasing your Zephyr project as open source? What kind of license do you use? Are there plans to monetize the project?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lars:&lt;/strong&gt; Yes, the solution is open source. I did not put a specific license on it, but I think Apache 2.0 would be the way to go. Many major companies use this license, including Google. When I worked on SimpleMouse, I did not think about monetizing the project—that was not my goal. But I also think it would make sense to try to put it into production in some way, and with this comes cost. The ultimate goal is to make it available. I’d love to see it being implemented at a low cost and on a large scale.&lt;/p&gt;
</content>
      <author>
          <name>Monika Janota</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Community highlight: Olutimilehin Olushuyi</title>
      <link href="https://web.dev/community-highlight-shuyi/"/>
      <updated>2022-11-09T00:00:00Z</updated>
      <id>https://web.dev/community-highlight-shuyi/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;em&gt;This post highlights a community expert, as a part of &lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra White&lt;/strong&gt;: How&#39;d you get started with web accessibility?&lt;/p&gt;
&lt;figure data-float=&quot;right&quot;&gt;
&lt;img alt=&quot;Olutimilehin Olushuyi&amp;#x27;s headshot.&quot; decoding=&quot;async&quot; height=&quot;334&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 350px) 350px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/gAeaexQOr9TO1FaNvpqb.jpeg?auto=format&amp;w=700 700w&quot; width=&quot;350&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Olutimilehin Olushuyi (Shuyi)&lt;/strong&gt;: Okay, so, it&#39;s a funny story. I&#39;m a lawyer.
I realized in my final year of school, I didn&#39;t want to practice law for the
rest of my life. So, I tried to drop out of school, but my dean and &amp;quot;school
mother,&amp;quot; &lt;a href=&quot;https://www.iclrs.org/ayodele-atsenuwa/&quot; rel=&quot;noopener&quot;&gt;Professor Ayodele Atsenuwa&lt;/a&gt;,
said, &amp;quot;Let&#39;s talk about this. You&#39;re in your final year—just finish it.&amp;quot;&lt;/p&gt;
&lt;p&gt;Ultimately, I&#39;m happy she said that, and I&#39;m happy I finished, because it&#39;s
been helping me in my accessibility work. Professor Atsenuwa asked me what I
wanted to do instead, and I had no idea.&lt;/p&gt;
&lt;p&gt;I started to look up new career opportunities, and got in touch with some
people who wanted to build a startup and needed a lawyer. That opportunity
wasn&#39;t the right fit, but that was the first time I knew people wrote code for
all of the products we use. I thought, &amp;quot;I can pick this up.&amp;quot; I started to teach
myself HTML and CSS. Then, I got to JavaScript and … [laughs] JavaScript did
JavaScript things, so I went back to focus on my front-end semantic languages.&lt;/p&gt;
&lt;p&gt;I came across the work of &lt;a href=&quot;https://piccalil.li/&quot; rel=&quot;noopener&quot;&gt;Andy Bell&lt;/a&gt; and
&lt;a href=&quot;https://heydonworks.com/&quot; rel=&quot;noopener&quot;&gt;Heydon Pickering&lt;/a&gt;. I purchased
&lt;a href=&quot;https://every-layout.dev/&quot; rel=&quot;noopener&quot;&gt;Every Layout&lt;/a&gt;, and it changed my life. Andy kept
mentioning accessibility, but I didn&#39;t know what that meant in this context. I
realized I may be able to work in web development without needing to know how
to write JavaScript!&lt;/p&gt;
&lt;p&gt;I reached out to Heydon and he was very receptive, very responsive. It seems
everyone in the accessibility field is that way, and I&#39;m grateful for that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I&#39;d definitely agree, everyone I&#39;ve spoken with has been so kind
and so helpful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: Absolutely. Currently, I do a lot more work in advocacy. I&#39;m based
in Nigeria, a country where web accessibility is not mandated by law. The
Discrimination Against Persons with Disabilities Act passed sometime in 2018.
But there&#39;s no web accessibility law, only law about physical accessibility.
It&#39;s like the USA&#39;s Americans with Disabilities Act (ADA). Our law is poorly
structured, but better than nothing.&lt;/p&gt;
&lt;p&gt;I realized if I&#39;m going to have any chance to make a difference and become an
accessibility focused developer, first I have to make the ecosystem aware of
accessibility needs. I started tweeting about accessibility advocacy. I talked
to companies and brands, whose buy-in is needed to get accessibility to work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I bet your legal background is incredibly useful in working with
accessibility. You can actually read the new legislation and understand it in a
way that the average person won&#39;t. That includes an average developer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I think one of the biggest gifts from my legal background is that I
can sit through unending pages of background materials, really lengthy
documents, without getting tired. I just fold my legs, put my laptop up, and
start to read. And read. And read. It&#39;s got advantages,&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I mean … I&#39;m jealous, that&#39;s a great skill to have. Do you think
you&#39;d ever work with the government to get a digital accessibility law passed?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I&#39;ll be honest, I don&#39;t think so. Engaging with the government is a
different ball game. It takes too long to get our government to do something,
especially as an individual. That kind of work is better for NGOs and other
organizations with staffing and resources to bring about change.&lt;/p&gt;
&lt;p&gt;The physical law took so much time to pass, and accessibility needs moved far
beyond what ended up in the law years ago. It&#39;s like the first draft was passed
even though the world has changed.&lt;/p&gt;
&lt;p&gt;Ultimately, we&#39;re happy there&#39;s something to rely on, no matter how outdated it
ended up being. There is a law to enforce.&lt;/p&gt;
&lt;h2 id=&quot;create-accessible-layouts&quot;&gt;Create accessible layouts &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-shuyi/#create-accessible-layouts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I read your article,  &lt;a href=&quot;https://www.smashingmagazine.com/2022/07/article-section-elements-accessibility/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; vs. &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;: How To Choose The Right One&lt;/a&gt;
in Smashing Magazine and the &lt;a href=&quot;https://twitter.com/ShuyiOlutimi/status/1455244970345082884?s=20&amp;amp;t=msdrhIBdSXGiEkc2pg0mOA&quot; rel=&quot;noopener&quot;&gt;Twitter thread&lt;/a&gt;
that inspired it. What would you say is one big takeaway, what&#39;s the one thing
you want from web developers?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: Developers must read the content before they begin building layouts.&lt;/p&gt;
&lt;p&gt;Originally, for my site design, I had just counted the number of paragraphs and
put them in sections and articles, without much thought. But,
&lt;a href=&quot;https://twitter.com/gracesnow/status/1455297078297518085&quot; rel=&quot;noopener&quot;&gt;someone drew my attention to the misuse of sections&lt;/a&gt;—it
was the first time I thought about it. Reading the content is one thing you can
do to make a better product.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: When I was a developer, I often had freelance clients say, &amp;quot;Oh,
just build something for us and we&#39;ll fill the content in later.&amp;quot; And sure,
there are some pages that have automatic context, like a contact page. But
knowing how many pages to build, and what kind of custom support was needed,
that could only be answered when I got the content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: Before knowing what I know, my best client would give me general
design ideas, and I&#39;d built out a site with a bunch of lorem ipsum. I&#39;ll figure
all that stuff out. But, when you realize how much the content infrastructure
affects users on the web, you realize just how much of the standard process for
building things on the web is actually flawed. You must be intentional when you
build things.&lt;/p&gt;
&lt;p&gt;So much accessibility infrastructure work doesn&#39;t get attention at all, and it
breaks my heart.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Take the Learn Accessibility module on &lt;a href=&quot;https://web.dev/learn/accessibility/structure&quot;&gt;Content structure&lt;/a&gt; to read about semantic HTML, landmarks, data tables, and more. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: How did you do your research to make sure the advice you gave in
the article was correct?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: First, I separated the sources of information—that&#39;s something
you do in law, separating primary and secondary sources. The primary sources
are the actual law (like the ADA and Nigeria&#39;s laws) and the secondary sources
are what experts interpret from the law.&lt;/p&gt;
&lt;p&gt;I decided to refer only to the primary sources: the HTML, WCAG, and WAI-ARIA
specs. I read other people&#39;s works, a lot of good work. But, at the end of the
day, the opinions were so divergent, I decided I could only take them as useful
context but not rely on them as having the right answers.&lt;/p&gt;
&lt;h2 id=&quot;build-an-accessible-community&quot;&gt;Build an accessible community &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-shuyi/#build-an-accessible-community&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You mentioned trying to shape your Twitter feed into a place for
accessibility. Have you had many other conversations on Twitter since the
Smashing Magazine article&#39;s publication about what you learned?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: For the first couple of days, I couldn&#39;t make good sense of Twitter.
So many people followed me, like 200+ people. At first I was excited, but then
I was scared. Like, I&#39;m just starting out, don&#39;t follow me for a bunch of sage
wisdom. I was added to a lot of Twitter lists.&lt;/p&gt;
&lt;p&gt;But like, I&#39;m a person. I tweet about a lot of vague, non-accessibility,
non-web developer stuff. I don&#39;t want to let people down. Don&#39;t follow me just
because of accessibility! I&#39;ll feel like I&#39;ll let you down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: [laughs] I mean, I think a lot of people think that. I certainly
do about my Twitter persona.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: Most responses to the article itself were positive. I got one
response to the article which was a bit controversial. &lt;a href=&quot;https://www.smashingmagazine.com/author/vitaly-friedman/&quot; rel=&quot;noopener&quot;&gt;Vitaly&lt;/a&gt; was my
editor, and he reached out directly to share
&lt;a href=&quot;https://www.smashingmagazine.com/2022/07/article-section-elements-accessibility/#1659357715965608590&quot; rel=&quot;noopener&quot;&gt;the comment&lt;/a&gt;
and asked me to investigate. Turns out, the person was referencing the MDN docs
which said that all &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/article#usage_notes&quot; rel=&quot;noopener&quot;&gt;articles should have a heading element&lt;/a&gt;.
I recommended that the section should have a heading element based on the specs.&lt;/p&gt;
&lt;p&gt;The MDN docs recommend including the header but don&#39;t really explain what the
benefit is.&lt;/p&gt;
&lt;p&gt;The spec changes less frequently than user needs, of course, so as long as you
can back up your decision to change the way you build something, it&#39;s probably
okay.&lt;/p&gt;
&lt;p&gt;So, let me give an example. Let&#39;s say you&#39;re building a card component called
&amp;quot;Prices,&amp;quot; with three elements in it. Hayden Pickering would suggest putting
each card into a list element. That way, when someone using assistive
technology (AT) gets to that section, it&#39;s announced to them that there are
three items in the price list. You can style the list so that there are no
bullet points, make it look however you want, but it helps AT users get the
useful information first. If you wrapped each item in a div, you&#39;d just be
focused on the visual aspects, which doesn&#39;t help visually impaired users.
Think of people before design.&lt;/p&gt;
&lt;p&gt;I took that idea, and transposed it for a blog page. The blog posts are actually within a list element. That way, on entry to the page, the user is alerted that they are at one of some number of posts on the page.&lt;/p&gt;
&lt;p&gt;So, I stood by my recommendations in the article, and I will until I understand
why MDN makes the recommendation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Since the MDN docs are open source, will you suggest changes and
make updates there?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I&#39;ll be honest, I haven&#39;t yet made any open source
contributions. But, this is the kind of work I would like to be doing,
certainly more than working with the government.&lt;/p&gt;
&lt;h2 id=&quot;spec-versus-implementation&quot;&gt;Spec versus implementation &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-shuyi/#spec-versus-implementation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: It sounds like one big takeaway is that sometimes the spec says
one thing, but implementation and other external docs may suggest doing
something different. How does someone decide whose advice to follow?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I think about this a lot. I&#39;m not sure I have the required
experience to answer that question. We&#39;re always trying to future-proof. It&#39;s
good to make continuous enhancements as the web changes. That way, when the
spec is updated, you don&#39;t need to retrofit your site. What are the chances
that you make a choice and three years from now the spec changes.&lt;/p&gt;
&lt;p&gt;Every choice we make now is our best guess of what we think the future of the
web will look like, what direction we think the spec writers will go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: The web is constantly changing, one person can&#39;t have all of the
answers! Did the specs go through changes while you were writing?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I started writing my article before the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/Heading_Elements#multiple_h1_elements_on_one_page&quot; rel=&quot;noopener&quot;&gt;document outline model&lt;/a&gt;
was removed from the spec. This model suggested that heading levels should be
automatically calculated based on how deep the nesting was. But it was never
really implemented and that created a lot of issues for developers. The advice
to developers was to manually fix their headings.&lt;/p&gt;
&lt;p&gt;If the article had been published before the spec change, I probably would have
gone back and made that edit—it is in Smashing Magazine after all. But if
it had lived on my personal blog, would I have? Probably not. And that&#39;s just
talking about updating an article, not updating an entire website that&#39;s built
based on a changing spec.&lt;/p&gt;
&lt;p&gt;Do we expect developers to immediately change their websites when the spec
changes? Of course not. They make calculations as to what&#39;s best when they&#39;re
building their sites and live with those choices. The specs will change, the
specs may not have the answer.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-as-a-career&quot;&gt;Accessibility as a career &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-shuyi/#accessibility-as-a-career&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: How much of your time do you spend thinking about global
accessibility standards? Standards and laws are different around the world. I&#39;m
sure you&#39;ve read a lot of them, and I&#39;m sure some laws tell you to do the
opposite things. What would you do in those cases?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: I thought about launching a business for freelance accessibility
work. I went into a global web accessibility chat channel and asked for tips on
how to get started. &lt;a href=&quot;https://adrianroselli.com/&quot; rel=&quot;noopener&quot;&gt;Adrian Roselli&lt;/a&gt; reached out
and said, &amp;quot;Your clients will be relying on you to keep them compliant with laws
which could have major consequences. Before you offer your services, know what
region you have expertise in. Know what laws you&#39;re familiar with so that,
while you&#39;re making a living for yourself, you don&#39;t leave clients with huge
liabilities. They trust you to know the law.&amp;quot;&lt;/p&gt;
&lt;p&gt;Of course, so many businesses are seeking accessibility help because they are
legally required, and not just because it&#39;s the right thing. Capitalism is the
reason accessibility is being implemented. At the end of the day, it doesn&#39;t
matter why it happened, it matters that the product is accessible.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Learn more about the &lt;a href=&quot;https://web.dev/learn/accessibility/why/#business-impact&quot;&gt;business impact of digital accessibility&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;I put a pause on freelancing until I have full confidence that I can help
clients with the laws of their region. Standardization is critical, the efforts
and impact of WCAG cannot be overstated. Having a central framework of how the
web should work makes it easier for governments to rely on the same standard.
But of course, not every government will accept those standards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You&#39;ve gotten a lot of great advice from great people in your
journey into accessibility. Is there any other advice you wish you&#39;d gotten
before you decided to pursue this as a career?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: While it wouldn&#39;t have changed my career path, it would have been
nice to know that as noble as accessibility work is, it&#39;s greatly affected by
capitalism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: [laughs] Oh yes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: And I&#39;m a junior. I have a year of experience in accessibility.
Especially if you&#39;re based in Africa, like I am, there&#39;s a limited availability
of positions in accessibility. Companies are hiring managers, one person to
meet whatever legal requirements are needed. But I want to work on a team,
where I can learn and build skills.&lt;/p&gt;
&lt;p&gt;I was so excited to get to work without learning JavaScript—that I could
just learn the rules and help my team apply them. But the developer positions
at agencies require that I have JavaScript experience. I moved to a new city
and joined a JavaScript bootcamp so I can meet those requirements. For anyone
else on their accessibility journey, know that you must focus on building your
development skills first.&lt;/p&gt;
&lt;p&gt;I&#39;m not going to lie, I still don&#39;t like JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;do-one-thing-add-keyboard-focus&quot;&gt;Do one thing: add keyboard focus &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-shuyi/#do-one-thing-add-keyboard-focus&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: [laughs] Is JavaScript the reason I&#39;m now a tech writer instead of a developer? Yes. Yes, it is. I hate it so much. I wish you the best of luck in your boot camp.&lt;/p&gt;
&lt;p&gt;What&#39;s one thing you want developers to do to make their site accessible?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shuyi&lt;/strong&gt;: Keyboard focus. I am begging from the bottom of my heart. My
trackpad currently doesn&#39;t work, so when I&#39;m on the go, I rely on my keyboard
to navigate the web, and almost every website is horrible. Keyboard focus
doesn&#39;t just benefit disabled people.&lt;/p&gt;
&lt;p&gt;Building accessible platforms benefits everyone.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Take the Learn Accessibility module on &lt;a href=&quot;https://web.dev/learn/accessibility/focus/&quot;&gt;Keyboard focus&lt;/a&gt; to discover how to ensure all users can navigate your content. &lt;/div&gt;&lt;/aside&gt;
&lt;hr /&gt;
&lt;p&gt;Keep up with Shuyi&#39;s work on Twitter
&lt;a href=&quot;https://twitter.com/shuyiolutimi&quot; rel=&quot;noopener&quot;&gt;@shuyiolutimi&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Speedy CSS Tip! Animated Gradient Text</title>
      <link href="https://web.dev/speedy-css-tip-animated-gradient-text/"/>
      <updated>2022-11-03T00:00:00Z</updated>
      <id>https://web.dev/speedy-css-tip-animated-gradient-text/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;Hop over to &lt;a href=&quot;https://pen.new/&quot; rel=&quot;noopener&quot;&gt;CodePen&lt;/a&gt; and create a new pen.&lt;/p&gt;
&lt;p&gt;Create the markup for your text. Let&#39;s use a header with the word &amp;quot;Speedy&amp;quot;:&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;h1&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;boujee-text&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;Hello!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then, let&#39;s give our &lt;code&gt;body&lt;/code&gt; a darker &lt;code&gt;background-color&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;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 20%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;Bump up the &lt;code&gt;font-size&lt;/code&gt; on our text. Use &lt;code&gt;clamp&lt;/code&gt; to make it responsive:&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;.boujee-text&lt;/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;3rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25vmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 8rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;Create two custom properties for the colors we&#39;re going to use. Apply a &lt;code&gt;linear-gradient&lt;/code&gt; to the &lt;code&gt;background&lt;/code&gt; using those colors and rotate it by 90 degrees:&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;.boujee-text&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;--color-one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;15 90% 55%&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;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;--color-two&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40 95% 55%&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 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;3rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25vmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 8rem&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 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;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                90deg&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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;mark class=&quot;highlight-line highlight-line-active&quot;&gt;                &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-two&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;mark class=&quot;highlight-line highlight-line-active&quot;&gt;                &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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; 0 0 / 100% 100%&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Create a custom property that you can use for the horizontal background size. Use it for &lt;code&gt;background-size-x&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;.boujee-text&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;--bg-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;--color-one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;15 90% 55%&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 property&quot;&gt;--color-two&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40 95% 55%&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 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;3rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25vmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 8rem&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 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;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                90deg&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-two&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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; 0 0 / &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 100%&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 clip the background to the text set the &lt;code&gt;color&lt;/code&gt; to &lt;code&gt;transparent&lt;/code&gt;, and set &lt;code&gt;background-clip: text&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;.boujee-text&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;--bg-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;--color-one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;15 90% 55%&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 property&quot;&gt;--color-two&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40 95% 55%&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 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;3rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25vmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 8rem&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 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;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                90deg&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-two&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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; 0 0 / &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg-size&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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&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;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;background-clip&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;/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;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;code&gt;background-clip&lt;/code&gt; property needs prefixing in some browsers as &lt;code&gt;-webkit-background-clip&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;At this point, you could leave it there and experiment with the &lt;code&gt;background-position&lt;/code&gt; and the gradient used in the &lt;code&gt;background-image&lt;/code&gt;. Or, you could animate that gradient across your text. First, define a keyframe for the animation. This will use the &lt;code&gt;--bg-size&lt;/code&gt; custom property you defined earlier. A good example of scoped custom properties making maintenance easier for you.&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; move-bg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg-size&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;Then apply the animation using &lt;code&gt;animation&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;.boujee-text&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;--bg-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;--color-one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;15 90% 55%&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 property&quot;&gt;--color-two&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;40 95% 55%&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 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;3rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 25vmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 8rem&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 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;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                90deg&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-two&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 function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-one&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; 0 0 / &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg-size&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;background-clip&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; move-bg 8s infinite linear&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 take this further, you can wrap your animation code in a media query to respect your user&#39;s preferences for motion:&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;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.boujee-text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; move-bg 8s linear 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;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; move-bg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;background-position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--bg-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div style=&quot;height: 300px; 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/vYrGPNE?height=300&amp;theme-id=dark&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen vYrGPNE by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;Done! 🎉 You&#39;ve created some animated gradient text with CSS using scoped custom properties and &lt;code&gt;background-clip&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&#39;s this tip in its speedy video form! ⚡️&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/v6NHBhtbffb91Ls0D7No.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Prefer this in &lt;a href=&quot;https://twitter.com/jh3yy/status/1517629642064150529&quot; rel=&quot;noopener&quot;&gt;tweet form&lt;/a&gt;? 🐦&lt;/p&gt;
&lt;p&gt;Stay Awesome! ʕ •ᴥ•ʔ&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Hero image by &lt;a href=&quot;https://unsplash.com/@lemonvlad&quot; rel=&quot;noopener&quot;&gt;Vladislav Klapin&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/speedy-text&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Jhey Tompkins</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>New patterns for media apps</title>
      <link href="https://web.dev/new-patterns-for-media-apps/"/>
      <updated>2022-11-03T00:00:00Z</updated>
      <id>https://web.dev/new-patterns-for-media-apps/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;Let&#39;s welcome our new collection of &lt;a href=&quot;https://web.dev/patterns/media&quot;&gt;media patterns&lt;/a&gt; to help you create modern media experiences on the web for great audio and video playback:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/patterns/media/audio-effects/&quot;&gt;Use the Web Audio API to add effects to audio sources&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/patterns/media/media-session/&quot;&gt;Let the user control media playback on the lock screen, in a widget, or with hardware keys&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/patterns/media/microphone-record/&quot;&gt;Record audio from the user&#39;s microphone&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/patterns/media/picture-in-picture/&quot;&gt;Create a custom Picture-in-Picture button for your video player&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/patterns/media/screen-record/&quot;&gt;Record the user&#39;s screen&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We hope these patterns will help you build amazing apps, and we&#39;re looking forward to your feedback! You can provide feedback by tweeting at &lt;a href=&quot;https://twitter.com/ChromiumDev&quot; rel=&quot;noopener&quot;&gt;@ChromiumDev&lt;/a&gt; or &lt;a href=&quot;https://github.com/GoogleChrome/web.dev/issues/new/choose&quot; rel=&quot;noopener&quot;&gt;filing an Issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/photos/plrlb68XPqI&quot; rel=&quot;noopener&quot;&gt;Kenny Eliason&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>François Beaufort</name>
        </author><author>
          <name>Tony Conway</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>New to the web platform in October</title>
      <link href="https://web.dev/web-platform-10-2022/"/>
      <updated>2022-10-31T00:00:00Z</updated>
      <id>https://web.dev/web-platform-10-2022/</id>
      <content type="text/html" mode="escaped">&lt;h2 id=&quot;stable-browser-releases&quot;&gt;Stable browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#stable-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In October, &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/106&quot; rel=&quot;noopener&quot;&gt;Firefox 106&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-107/&quot; rel=&quot;noopener&quot;&gt;Chrome 107&lt;/a&gt;, and &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-16_1-release-notes&quot; rel=&quot;noopener&quot;&gt;Safari 16.1&lt;/a&gt; became stable. Let&#39;s take a look at what this means for the web platform.&lt;/p&gt;
&lt;h3 id=&quot;animation-of-grid-tracks&quot;&gt;Animation of grid tracks &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#animation-of-grid-tracks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thanks to the work of our contributors at Microsoft, Chrome is now able to interpolate &lt;code&gt;grid-template-columns&lt;/code&gt; and &lt;code&gt;grid-template-rows&lt;/code&gt; values. This means that grid layouts can smoothly transition between states, instead of snapping at the halfway point of an animation or transition.&lt;/p&gt;
&lt;figure&gt;
&lt;div 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://codepen.io/web-dot-dev/embed/XWqVowx?height=480&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen XWqVowx by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;figcaption&gt;Hover over the avatars to see the animation. This example is from the article &lt;a href=&quot;https://web.dev/css-animated-grid-layouts/&quot;&gt;CSS animated grid layouts&lt;/a&gt;, where you can find out more.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 107, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        107
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 66, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        66
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 107, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        107
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        16
      &lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h3 id=&quot;additions-to-getdisplaymedia&quot;&gt;Additions to &lt;code&gt;getDisplayMedia()&lt;/code&gt; &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#additions-to-getdisplaymedia&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Also in Chrome are some additions to &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/MediaDevices/getDisplayMedia&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;getDisplayMedia()&lt;/code&gt;&lt;/a&gt; that aim to prevent &lt;a href=&quot;https://developer.chrome.com/blog/avoiding-oversharing-when-screen-sharing/&quot; rel=&quot;noopener&quot;&gt;accidental oversharing when screen sharing&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/web-platform/screen-sharing-controls/#displaySurface&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;displaySurface&lt;/code&gt;&lt;/a&gt; option can indicate that the web app prefers to offer a specific display surface type (tabs, windows, or screens).&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/web-platform/screen-sharing-controls/#surfaceSwitching&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;surfaceSwitching&lt;/code&gt;&lt;/a&gt; option indicates whether Chrome should allow the user to dynamically switch between shared tabs.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/web-platform/screen-sharing-controls/#selfBrowserSurface&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;selfBrowserSurface&lt;/code&gt;&lt;/a&gt; option can be used to prevent the user from sharing the current tab. This avoids the &amp;quot;hall of mirrors&amp;quot; effect.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/web-platform/screen-sharing-controls/#systemAudio&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;systemAudio&lt;/code&gt;&lt;/a&gt; option ensures Chrome only offers relevant audio-capture to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Safari 16.1 also includes support for &lt;code&gt;getDisplayMedia&lt;/code&gt;, adding support for capturing a specific Safari window.&lt;/p&gt;
&lt;h3 id=&quot;testing-for-support-of-font-technology-and-features-from-css&quot;&gt;Testing for support of font technology and features from CSS &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#testing-for-support-of-font-technology-and-features-from-css&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firefox has added the &lt;code&gt;font-tech()&lt;/code&gt; and &lt;code&gt;font-format()&lt;/code&gt; functions to feature queries with &lt;code&gt;@supports&lt;/code&gt;. The following example tests for support of &lt;a href=&quot;https://developer.chrome.com/blog/colrv1-fonts/&quot; rel=&quot;noopener&quot;&gt;COLRv1 fonts&lt;/a&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 function&quot;&gt;font-tech&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;color-COLRv1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can find more examples &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@supports#testing_for_the_support_of_a_font_technology&quot; rel=&quot;noopener&quot;&gt;on MDN&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scroll-to-text-fragment&quot;&gt;Scroll to text fragment &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#scroll-to-text-fragment&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari 16.1 includes support for &lt;a href=&quot;https://wicg.github.io/scroll-to-text-fragment/&quot; rel=&quot;noopener&quot;&gt;scroll to text fragment&lt;/a&gt; which adds support for navigating to a URL with a particular text fragment specified.&lt;/p&gt;
&lt;h3 id=&quot;avif-support&quot;&gt;AVIF support &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#avif-support&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari 16 included support for still AVIF images, Safari 16.1 includes support for animated AVIF images on macOS Ventura, iOS 16, and iPadOS 16.&lt;/p&gt;
&lt;h3 id=&quot;web-push-for-safari&quot;&gt;Web Push for Safari &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#web-push-for-safari&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari 16.1 brings Web Push support to Safari on macOS Ventura. This uses the Push API and Notifications API, you can read more about this in the article &lt;a href=&quot;https://webkit.org/blog/12945/meet-web-push/&quot; rel=&quot;noopener&quot;&gt;Meet Web Push&lt;/a&gt;. Web Push landing in Safari means that it is now available across all three major engines.&lt;/p&gt;
&lt;h2 id=&quot;beta-browser-releases&quot;&gt;Beta browser releases &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/web-platform-10-2022/#beta-browser-releases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beta browser versions give you a preview of things that will be in the next stable version of the browser. It&#39;s a great time to test new features, or removals, that could impact your site before the world gets that release. New betas this month are &lt;a href=&quot;https://developer.chrome.com/blog/chrome-108-beta/&quot; rel=&quot;noopener&quot;&gt;Chrome 108&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/107&quot; rel=&quot;noopener&quot;&gt;Firefox 107&lt;/a&gt;, and &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-16_2-release-notes&quot; rel=&quot;noopener&quot;&gt;Safari 16.2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Chrome 108 includes support for the &lt;code&gt;avoid&lt;/code&gt; value of the CSS fragmentation properties &lt;code&gt;break-before&lt;/code&gt;, &lt;code&gt;break-after&lt;/code&gt;, and &lt;code&gt;break-inside&lt;/code&gt; when printing. This value tell the browser to avoid breaking before, after or inside the element it is applied to. For example, the following CSS avoids a figure being broken at a page break.&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;figure&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;break-inside&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; avoid&lt;span 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;Chrome 108 starts to roll out a change to the way overflow behaves on replaced elements, which may cause visual changes in some circumstances. Read the article &lt;a href=&quot;https://developer.chrome.com/blog/overflow-replaced-elements/&quot; rel=&quot;noopener&quot;&gt;A change to overflow on replaced elements in CSS&lt;/a&gt; for more details and to see how to address any issues you see.&lt;/p&gt;
&lt;p&gt;There&#39;s a change to how the Layout Viewport behaves in Chrome on Android when the on-screen keyboard is shown. Read &lt;a href=&quot;https://developer.chrome.com/blog/viewport-resize-behavior/&quot; rel=&quot;noopener&quot;&gt;Prepare for viewport resize behavior changes coming to Chrome on Android&lt;/a&gt; to learn more and find out how to prepare for this shipping to stable next month.&lt;/p&gt;
&lt;p&gt;Also in Chrome are the new CSS Viewport Units. These include small (&lt;code&gt;svw&lt;/code&gt;, &lt;code&gt;svh&lt;/code&gt;, &lt;code&gt;svi&lt;/code&gt;, &lt;code&gt;svb&lt;/code&gt;, &lt;code&gt;svmin&lt;/code&gt;, &lt;code&gt;svmax&lt;/code&gt;), large (&lt;code&gt;lvw&lt;/code&gt;, &lt;code&gt;lvh&lt;/code&gt;, &lt;code&gt;lvi&lt;/code&gt;, &lt;code&gt;lvb&lt;/code&gt;, &lt;code&gt;lvmin&lt;/code&gt;, &lt;code&gt;lvmax&lt;/code&gt;), dynamic (&lt;code&gt;dvw&lt;/code&gt;, &lt;code&gt;dvh&lt;/code&gt;, &lt;code&gt;dvi&lt;/code&gt;, &lt;code&gt;dvb&lt;/code&gt;, &lt;code&gt;dvmin&lt;/code&gt;, &lt;code&gt;dvmax&lt;/code&gt;), and logical (&lt;code&gt;vi&lt;/code&gt;, &lt;code&gt;vb&lt;/code&gt;) units. These units are already implemented in Firefox and Safari.&lt;/p&gt;
&lt;p&gt;Firefox 107 enables COLRv1 font support, joining Chrome in supporting this font technology. Also in fonts, Chrome 108 adds support for the &lt;code&gt;font-tech()&lt;/code&gt; and &lt;code&gt;font-format()&lt;/code&gt; functions to feature queries with &lt;code&gt;@supports&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Firefox also adds &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/contain-intrinsic-size&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;contain-intrinsic-size&lt;/code&gt;&lt;/a&gt; support, joining Chrome to make two browsers with support for this feature.&lt;/p&gt;
&lt;p&gt;Safari 16.2 Beta includes a bunch of CSS fixes including sizing and scroll snap.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ahmedzaid?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;ahmed zid&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Rachel Andrew</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Building Chrometober!</title>
      <link href="https://web.dev/building-chrometober/"/>
      <updated>2022-10-31T00:00:00Z</updated>
      <id>https://web.dev/building-chrometober/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;Following on from &lt;a href=&quot;https://designcember.com/&quot; rel=&quot;noopener&quot;&gt;Designcember&lt;/a&gt;, we wanted to build Chrometober for you this year as a way to highlight and share web content from the community and Chrome team. Designcember showcased the use of Container Queries, but this year we&#39;re showcasing the CSS scroll-linked animations API.&lt;/p&gt;
&lt;p&gt;Check out the scrolling book experience at &lt;a href=&quot;https://web.dev/chrometober-2022&quot;&gt;web.dev/chrometober-2022&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/nIBMYSqI5NRCFoLSbeNh.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal of the project was to deliver a whimsical experience highlighting the scroll-linked animations API. But, whilst being whimsical, the experience needed to be responsive and accessible too. The project has also been a great way to test drive the API polyfill that is in active development; that, as well as trying different techniques and tools in combination. And all with a festive Halloween theme!&lt;/p&gt;
&lt;p&gt;Our team structure looked like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/intent/follow?screen_name=rudepetsclub&quot; rel=&quot;noopener&quot;&gt;Tyler Reed&lt;/a&gt;: Illustration and design&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/intent/follow?screen_name=jh3yy&quot; rel=&quot;noopener&quot;&gt;Jhey Tompkins&lt;/a&gt;: Architectural and creative lead&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/intent/follow?screen_name=una&quot; rel=&quot;noopener&quot;&gt;Una Kravets&lt;/a&gt;: Project lead&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/intent/follow?screen_name=bramus&quot; rel=&quot;noopener&quot;&gt;Bramus Van Damme&lt;/a&gt;: Site contributor&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/intent/follow?screen_name=argyleink&quot; rel=&quot;noopener&quot;&gt;Adam Argyle&lt;/a&gt;: Accessibility review&lt;/li&gt;
&lt;li&gt;Aaron Forinton: Copywriting&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;drafting-a-scrollytelling-experience&quot;&gt;Drafting a scrollytelling experience &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#drafting-a-scrollytelling-experience&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ideas for Chrometober started flowing at our first team offsite back in May 2022. A collection of scribbles had us thinking of ways in which a user could scroll their way along some form of storyboard. Inspired by video games, we considered a scrolling experience through scenes such as graveyards and a haunted house.&lt;/p&gt;
&lt;img alt=&quot;A notebook lies on a desk with various doodles and scribbles related to the project.&quot; decoding=&quot;async&quot; height=&quot;600&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/5teCNthBhFithDxWLXMv.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;It was exciting to have the creative freedom to take my first Google project in an unexpected direction. This was an early prototype of how a user might navigate through the content.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/MlfvDw4pl0NqRaRnu2rC.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/gOKbBVz?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen gOKbBVz by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;As the user scrolls sideways, the blocks rotate and scale in. But I decided to move away from this idea out of concern for how we could make this experience great for users on devices of all sizes. Instead, I leaned towards the design of something I&#39;d made in the past. In 2020, I was fortunate to have access to &lt;a href=&quot;https://greensock.com/scrolltrigger/&quot; rel=&quot;noopener&quot;&gt;GreenSock&#39;s ScrollTrigger&lt;/a&gt; to build release demos.&lt;/p&gt;
&lt;p&gt;One of the demos I’d built was a 3D-CSS book where the pages turned as you scrolled, and this felt much more appropriate for what we wanted for Chrometober. The scroll-linked animations API is a perfect swap for that functionality. It also works well with &lt;code&gt;scroll-snap&lt;/code&gt;, as you&#39;ll see!&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/FlOQAUsk6Md9Rya04Gkm.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/WNybYeP?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen WNybYeP by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;Our illustrator for the project, &lt;a href=&quot;https://www.rudepets.club/&quot; rel=&quot;noopener&quot;&gt;Tyler Reed&lt;/a&gt;, was great at altering the design as we changed ideas. Tyler did a fantastic job of taking all the creative ideas thrown at him and bringing them to life. It was a lot of fun brainstorming ideas together. A big part of how we wanted this to work was having features broken up into isolated blocks. That way, we could compose them into scenes and then pick and choose what we brought to life.&lt;/p&gt;
&lt;img alt=&quot;One of the composition scenes featuring a snake, a coffin with arms coming out, a fox with a wand at a cauldron, a tree with a spooky face, and a gargoyle holding a pumpkin lantern.&quot; decoding=&quot;async&quot; height=&quot;564&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/j4ecLHXusYXPiPJxlPtB.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The main idea was that, as the user made their way through the book, they could access blocks of content. They could also interact with dashes of whimsy, including the Easter eggs we had built into the experience; for example, a portrait in a haunted house, whose eyes followed your pointer, or subtle animations triggered by media queries. These ideas and features would be animated on scroll. An early idea was a zombie bunny that would rise and translate along the x-axis on user scroll.&lt;/p&gt;
&lt;h2 id=&quot;getting-familiar-with-the-api&quot;&gt;Getting familiar with the API &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#getting-familiar-with-the-api&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we could start playing with individual features and Easter eggs, we needed a book. So we decided to turn this into a chance to test the featureset for the emerging, &lt;a href=&quot;https://drafts.csswg.org/scroll-animations-1/&quot; rel=&quot;noopener&quot;&gt;CSS scroll-linked animations API&lt;/a&gt;. The scroll-linked animations API is not currently supported in any browsers. However, while developing the API, the engineers on the interactions team have been working on a &lt;a href=&quot;https://github.com/flackr/scroll-timeline&quot; rel=&quot;noopener&quot;&gt;polyfill&lt;/a&gt;. This provides a way to test out the shape of the API as it develops. That means we could use this API today, and fun projects like this are often a great place to try out experimental features, and to provide feedback. Find out what we learned and the feedback we were able to provide, &lt;a href=&quot;https://web.dev/building-chrometober/#what-we-learned&quot;&gt;later in the article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At a high level, you can use this API to link animations to scroll. It&#39;s important to note that you can&#39;t trigger an animation on scroll—this is something that could come later. Scroll-linked animations also fall into two main categories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Those that react to scroll position.&lt;/li&gt;
&lt;li&gt;Those that react to an element&#39;s position in its scrolling container.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To create the latter, we use a &lt;code&gt;ViewTimeline&lt;/code&gt; applied via an &lt;code&gt;animation-timeline&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of what using &lt;code&gt;ViewTimeline&lt;/code&gt; looks like 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;.element-moving-in-viewport&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-timeline-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-timeline-axis&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.element-scroll-linked&lt;/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; rotate both linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; enter 0%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-end-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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; rotate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 360deg&lt;span class=&quot;token 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 create a &lt;code&gt;ViewTimeline&lt;/code&gt; with &lt;code&gt;view-timeline-name&lt;/code&gt; and define the axis for it. In this example, &lt;code&gt;block&lt;/code&gt; refers to &lt;a href=&quot;https://web.dev/learn/css/logical-properties/&quot;&gt;logical &lt;code&gt;block&lt;/code&gt;&lt;/a&gt;. The animation gets linked to scroll with the &lt;code&gt;animation-timeline&lt;/code&gt; property. &lt;code&gt;animation-delay&lt;/code&gt; and &lt;code&gt;animation-end-delay&lt;/code&gt; (at the time of writing) are how we define phases.&lt;/p&gt;
&lt;p&gt;These phases define the points at which the animation should get linked in relation to an element&#39;s position in its scrolling container. In our example, we&#39;re saying start the animation when the element enters (&lt;code&gt;enter 0%&lt;/code&gt;) the scrolling container. And finish when it has covered 50% (&lt;code&gt;cover 50%&lt;/code&gt;) of the scrolling container.&lt;/p&gt;
&lt;p&gt;Here&#39;s our demo in action:&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/xVK0tJ70MsfN6ZYmtsaS.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/jOKEQWj?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen jOKEQWj by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;You could also link an animation to the element that is moving in the viewport. You can do this by setting the &lt;code&gt;animation-timeline&lt;/code&gt; to be the element&#39;s &lt;code&gt;view-timeline&lt;/code&gt;. This is good for scenarios such as list animations. The behavior is similar to how you might animate elements &lt;a href=&quot;https://twitter.com/jh3yy/status/1558551933064884225?s=20&amp;amp;t=A1hdziw2Oz5MgkEjTZS-2Q&quot; rel=&quot;noopener&quot;&gt;upon entry using &lt;code&gt;IntersectionObserver&lt;/code&gt;&lt;/a&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;element-moving-in-viewport&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-timeline-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;view-timeline-axis&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;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scale both linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; enter 0%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-end-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;animation-timeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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; scale&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;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;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;With this,&amp;quot;Mover&amp;quot; scales up as it enters the viewport, triggering the rotation of &amp;quot;Spinner&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/FnxZiRz1i8NevSCcxeag.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/MWXYzeY?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen MWXYzeY by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&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; Do check out &lt;a href=&quot;https://drafts.csswg.org/scroll-animations-1/&quot;&gt;the spec&lt;/a&gt; for more in-depth details about the API. Also look out for an article dedicated to scroll-linked animations coming soon! &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;What I found from experimenting was that the API works very well with &lt;a href=&quot;https://web.dev/css-scroll-snap/&quot;&gt;scroll-snap&lt;/a&gt;. Scroll-snap combined with &lt;code&gt;ViewTimeline&lt;/code&gt; would be a great fit for snapping page turns in a book.&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; Feel free to check out my &lt;a href=&quot;https://codepen.io/collection/qOPdLq&quot;&gt;scroll-linked animations API collection&lt;/a&gt; over on CodePen. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;prototyping-the-mechanics&quot;&gt;Prototyping the mechanics &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#prototyping-the-mechanics&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After some experimenting, I was able to get a book prototype working. You scroll horizontally to turn the pages of the book.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/JZJZyFvVruWFy50EYBb8.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/JjZoeEN?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen JjZoeEN by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;In the demo, you can see the different triggers highlighted with dashed borders.&lt;/p&gt;
&lt;p&gt;The markup looks a little like this:&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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;book-placeholder&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 7&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;br /&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;page page--cover page--cover-front&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;data-scroll-target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--index&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;page__paper&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;page__side page__side--front&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;page__side page__side--back&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Markup for other pages here --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;intro spacer&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-scroll-intro&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;scale trigger&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-scroll-trigger&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;page trigger&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Markup for other triggers here --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As you scroll, the pages of the book turn, but snap open or closed. This is dependent on the scroll-snap alignment of the triggers.&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;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--trigger-count&lt;span class=&quot;token punctuation&quot;&gt;)&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&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; scroll&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body &gt; [data-scroll-trigger]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;10rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 10vw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 300px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;body &gt; [data-scroll-trigger]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-snap-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This time, we do not connect the &lt;code&gt;ViewTimeline&lt;/code&gt; in CSS, but use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Web_Animations_API&quot; rel=&quot;noopener&quot;&gt;Web Animations API&lt;/a&gt; in JavaScript. This has the added benefit of being able to loop over a set of elements and generate the &lt;code&gt;ViewTimeline&lt;/code&gt; we need, instead of creating them each by hand.&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; triggers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[data-scroll-trigger]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; commonProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;phase&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;enter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;endDelay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;phase&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;enter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&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;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;both&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;setupPage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;trigger&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[data-scroll-target=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;trigger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data-scroll-trigger&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;]&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; viewTimeline &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ViewTimeline&lt;/span&gt;&lt;span class=&quot;token punctuation&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;subject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; trigger&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;inline&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  target&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;br /&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;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;translateZ(&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 punctuation&quot;&gt;(&lt;/span&gt;triggers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;px)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;translateZ(&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 punctuation&quot;&gt;(&lt;/span&gt;triggers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;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;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.75&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;translateZ(&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 punctuation&quot;&gt;(&lt;/span&gt;triggers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &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 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;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;timeline&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; viewTimeline&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      …commonProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.page__paper&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;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;br /&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;transform&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rotateY(0deg)&quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&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;&quot;rotateY(-180deg)&quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;timeline&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; viewTimeline&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      …commonProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; triggers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-scroll-trigger]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;triggers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;setupPage&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;For each trigger, we generate a &lt;code&gt;ViewTimeline&lt;/code&gt;. Then we animate the trigger&#39;s associated page using that &lt;code&gt;ViewTimeline&lt;/code&gt;. That links the page&#39;s animation to scroll. For our animation, we are rotating an element of the page on the y-axis to turn the page. We also translate the page itself on the z-axis so it behaves like a book.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/up1PL47mHnpZLbOfMJoX.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#putting-it-all-together&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once I&#39;d worked out the mechanism for the book, I could focus on bringing Tyler&#39;s illustrations to life.&lt;/p&gt;
&lt;h3 id=&quot;astro&quot;&gt;Astro &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#astro&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The team &lt;a href=&quot;https://web.dev/how-we-built-designcember/&quot;&gt;used Astro for Designcember&lt;/a&gt; in 2021 and I was keen to use it again for Chrometober. The developer experience of being able to break things up into components is well suited to this project.&lt;/p&gt;
&lt;p&gt;The book itself is a component. It is also a collection of page components. Each page has two sides and they have backdrops. The children of a page side are components which can be added, removed, and positioned with ease.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/6k7eoCK4ObUg9VMvWg0x.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;building-a-book&quot;&gt;Building a book &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#building-a-book&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was important for me to make the blocks easy to manage. I also wanted to make it easy for the rest of the team to make contributions.&lt;/p&gt;
&lt;p&gt;The pages at a high level are defined by a configuration array. Each page object in the array defines the content, backdrop, and other metadata for a page.&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; pages &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;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;marked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PageTwo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;backdrop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; spreadOne&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;darkBackdrop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; spreadOneDark&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 literal-property property&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PageThree&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;backdrop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; spreadTwo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;darkBackdrop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; spreadTwoDark&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 literal-property property&quot;&gt;aria&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;page 1&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&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 comment&quot;&gt;/* Obfuscated page objects */&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;These get passed to the &lt;code&gt;Book&lt;/code&gt; component.&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;Book&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{pages}&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;The &lt;code&gt;Book&lt;/code&gt; component is where the scrolling mechanism is applied and the pages of the book are created. The same mechanism from the prototype is used; but we share multiple instances of  &lt;code&gt;ViewTimeline&lt;/code&gt; that are created globally.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CHROMETOBER_TIMELINES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewTimeline&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;This way, we can share the timelines to be used elsewhere instead of recreating them. More on this later.&lt;/p&gt;
&lt;h3 id=&quot;page-composition&quot;&gt;Page composition &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#page-composition&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each page is a list item inside a list:&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 operator&quot;&gt;&amp;lt;&lt;/span&gt;ul &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;book&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    pages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;page&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; FrontSlot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;front&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; BackSlot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;back&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Page&lt;br /&gt;          index&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          cover&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cover&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          aria&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aria&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          backdrop&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;br /&gt;              &lt;span class=&quot;token literal-property property&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;front&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backdrop&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;front&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;darkBackdrop&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 literal-property property&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;back&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backdrop&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;back&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;darkBackdrop&lt;br /&gt;              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;front&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FrontSlot slot&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;front&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    &lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;back&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BackSlot slot&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;back&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    &lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Page&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;ul&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And the defined configuration gets passed to each &lt;code&gt;Page&lt;/code&gt; instance. The pages use Astro&#39;s &lt;a href=&quot;https://docs.astro.build/en/core-concepts/astro-components/#slots&quot; rel=&quot;noopener&quot;&gt;slot feature&lt;/a&gt; to insert content into each page.&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;li&lt;/span&gt;&lt;br /&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;{className}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;data-scroll-target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{target}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;`--index:$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;`&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{aria}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;page__paper&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;br /&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;page__side page__side--front&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{`Right&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;${index}`}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;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;{darkFront}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(prefers-color-scheme: dark)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;214&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{lightFront}&lt;/span&gt;&lt;br /&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;page__background page__background--right&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;214&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token 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;page__content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;front&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Markup for back page --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&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;This code is mostly for setting up structure. Contributors can work on the book’s content for the most part without having to touch this code.&lt;/p&gt;
&lt;h3 id=&quot;backdrops&quot;&gt;Backdrops &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#backdrops&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The creative shift towards a book made splitting up the sections much easier, and each spread of the book is a scene taken from the original design.&lt;/p&gt;
&lt;img alt=&quot;Page spread illustration from the book which features an apple tree in a graveyard. The graveyard has multiple headstones and there is a bat in the sky in front of a large moon.&quot; decoding=&quot;async&quot; height=&quot;560&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/N3UtScgJr16t0Xp4vDN7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;As we had decided on an aspect ratio for the book, the backdrop for each page could have a picture element. Setting that element to 200% width and using &lt;code&gt;object-position&lt;/code&gt; based on page side does the trick.&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;.page__background&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&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;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&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;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.page__background--right&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;object-position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100% 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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/koKQdPSVpa7uARGLmcXL.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/RwJNOrO?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen RwJNOrO by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h3 id=&quot;page-content&quot;&gt;Page content &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#page-content&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s look at building out one of the pages. Page three features an owl that pops up in a tree.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/GYZvp3dT9l57lIfjO2wE.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It gets populated with a &lt;code&gt;PageThree&lt;/code&gt; component, as defined in the configuration. It’s an &lt;a href=&quot;https://docs.astro.build/en/core-concepts/astro-components/&quot; rel=&quot;noopener&quot;&gt;Astro component&lt;/a&gt; (&lt;code&gt;PageThree.astro&lt;/code&gt;). These components look like HTML files but they have a code fence at the top similar to frontmatter. This enables us to do things like import other components. The component for page three looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TreeOwl &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../TreeOwl/TreeOwl.astro&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; contentBlocks &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../assets/content-blocks.json&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ContentBlock &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../ContentBlock/ContentBlock.astro&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TreeOwl&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;&lt;span class=&quot;token class-name&quot;&gt;ContentBlock&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token spread&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;contentBlocks&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&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 attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;four&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;is:&lt;/span&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  .content-block--four {&lt;br /&gt;    left: 30%;&lt;br /&gt;    bottom: 10%;&lt;br /&gt;  }&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Again, pages are atomic in nature. They are built from a collection of features. Page three features a content block and the interactive owl, so there is a component for each.&lt;/p&gt;
&lt;p&gt;Content blocks are the links to content seen within the book. These are also driven by a configuration object.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;contentBlocks&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;one&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;New in Chrome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;blurb&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Lift your spirits with a round up of all the tools and features in Chrome.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;link&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.youtube.com/watch?v=qwdN1fJA_d8&amp;amp;list=PLNYkxOF6rcIDfz8XEA3loxY32tYh7CI3m&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    …otherBlocks&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 configuration gets imported where content blocks are required. Then the relevant block configuration gets passed to the &lt;code&gt;ContentBlock&lt;/code&gt; component.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&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;&lt;span class=&quot;token class-name&quot;&gt;ContentBlock&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token spread&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;contentBlocks&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&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 attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;four&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;There is also an example here of how we use the page&#39;s component as a place to position the content. Here, a content block gets positioned.&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;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;is:&lt;/span&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;.content-block--four&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30%&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; 10%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;But, the general styles for a content block are co-located with the component 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;.content-block&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0deg 0% 0% / 70%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--gray-0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;3vh&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--size-4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.75rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2vw&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--size-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 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;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As for our owl, it&#39;s an interactive feature—one of many in this project. This is a nice small example to go through that shows how we used the shared ViewTimeline that we created.&lt;/p&gt;
&lt;p&gt;At a high level, our owl component imports some SVG and inlines it using Astro&#39;s Fragment.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Owl &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../Features/Owl.svg?raw&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Fragment&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;set:&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Owl&lt;span class=&quot;token punctuation&quot;&gt;}&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;And the styles for positioning our owl are co-located with the component 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;.owl&lt;/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; 34%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10%&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; 34%&lt;span 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;There is one extra piece of styling that defines the &lt;code&gt;transform&lt;/code&gt; behavior for the owl.&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;.owl__owl&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform-origin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50% 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform-box&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fill-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The use of &lt;code&gt;transform-box&lt;/code&gt; affects the &lt;code&gt;transform-origin&lt;/code&gt;. It makes it relative to the object’s bounding box within the SVG. The owl scales up from the bottom center, hence the use of &lt;code&gt;transform-origin: 50% 100%&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The fun part is when we link the owl up to one of our generated &lt;code&gt;ViewTimeline&lt;/code&gt;s:&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; &lt;span class=&quot;token function-variable function&quot;&gt;setUpOwl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; owl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.owl__owl&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   owl&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;br /&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;translate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0% 110%&#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;br /&gt;       &lt;span class=&quot;token literal-property property&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0% 10%&#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;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;timeline&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CHROMETOBER_TIMELINES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;phase&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;enter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&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;endDelay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;phase&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;enter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&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;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;both&#39;&lt;/span&gt; &lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(prefers-reduced-motion: no-preference)&#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;matches&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;setUpOwl&lt;/span&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 block of code, we do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check for the user’s motion preferences.&lt;/li&gt;
&lt;li&gt;If they have no preference, link an animation of the owl to scroll.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the second part, the owl animates on the y-axis using the Web Animations API. Individual transform property &lt;code&gt;translate&lt;/code&gt; is used, and is linked to one &lt;code&gt;ViewTimeline&lt;/code&gt;. It&#39;s linked to &lt;code&gt;CHROMETOBER_TIMELINES[1]&lt;/code&gt; via the &lt;code&gt;timeline&lt;/code&gt; property. This is a &lt;code&gt;ViewTimeline&lt;/code&gt; that is generated for the page turns. This links the owl&#39;s animation to the page turn using the &lt;code&gt;enter&lt;/code&gt; phase. It defines that, when the page is 80% turned, start moving the owl. At 90%, the owl should finish its translation.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/GYZvp3dT9l57lIfjO2wE.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/KKewLKo?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen KKewLKo by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h2 id=&quot;book-features&quot;&gt;Book features &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#book-features&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now you&#39;ve seen the approach for building a page and how the project architecture works. You can see how it allows contributors to jump in and work on a page or feature of their choosing. Various features in the book have their animations linked to the book&#39;s page turning; for example, the bat that flies in and out on page turns.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/D9wLvoj1f8Ieddu9MGUm.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It also has elements that are powered by &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot; rel=&quot;noopener&quot;&gt;CSS animations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the content blocks were in the book, there was time to get creative with other features. This provided an opportunity to generate some different interactions, and try different ways to implement things.&lt;/p&gt;
&lt;h3 id=&quot;keeping-things-responsive&quot;&gt;Keeping things responsive &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#keeping-things-responsive&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Responsive viewport units size the book and its features. However, keeping fonts responsive was an interesting challenge. Container query units are a good fit here. They aren&#39;t supported everywhere yet, though. The size of the book is set, so we don&#39;t need a container query. An inline container query unit can be generated with &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/calc&quot; rel=&quot;noopener&quot;&gt;CSS &lt;code&gt;calc()&lt;/code&gt;&lt;/a&gt; and used for font sizing.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.book-placeholder&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--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;12rem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 72vw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 80vmin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 360 / 504&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--cqi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0.01 * &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--aspect-ratio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.content-block h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--gray-0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;0.6rem&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;--cqi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.content-block :is(p, a)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-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;0.6rem&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;--cqi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 3&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/kXldZFb8uwtGdIBV6xY6.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;pumpkins-shine-at-night&quot;&gt;Pumpkins shine at night &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#pumpkins-shine-at-night&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Those with a keen eye may have noticed the use of &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements when discussing the page backdrops earlier. &lt;a href=&quot;https://twitter.com/una&quot; rel=&quot;noopener&quot;&gt;Una&lt;/a&gt; was keen to have an interaction that reacted to color scheme preference. As a result, the backdrops support both light and dark modes with different variants. Because you can use media queries with the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element, it&#39;s a great way to provide two backdrop styles. The &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; element queries for color scheme preference, and shows the appropriate backdrop.&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;{darkFront}&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(prefers-color-scheme: dark)&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;214&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;{lightFront}&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;page__background page__background--right&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;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token 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;214&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;150&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;You could introduce other changes based on that color scheme preference. The pumpkins on page two react to a user&#39;s color scheme preference. The SVG used has circles that represent flames, which scale up and animate in dark mode.&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;.pumpkin__flame,&lt;br /&gt; .pumpkin__flame circle&lt;/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-box&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fill-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;transform-origin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50% 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;.pumpkin__flame&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;.pumpkin__flame circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scale 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&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;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token selector&quot;&gt;.pumpkin__flame&lt;/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; pumpkin-flicker 3s &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * -1s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; infinite linear&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;.pumpkin__flame circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token property&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;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; pumpkin-flicker&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token selector&quot;&gt;50%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token property&quot;&gt;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;br /&gt;     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/PYuFOFPEG5RjwVySed3J.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;is-this-portrait-watching-you&quot;&gt;Is this portrait watching you? &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#is-this-portrait-watching-you&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you check out page 10, you might notice something. You&#39;re being watched! The eyes of the portrait will follow your pointer as you move around the page. The trick here is to map the pointer location to a translate value, and pass it through to CSS.&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; &lt;span class=&quot;token function-variable function&quot;&gt;mapRange&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;inputLower&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; inputUpper&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputLower&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputUpper&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;INPUT_RANGE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputUpper &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; inputLower&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;OUTPUT_RANGE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; outputUpper &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; outputLower&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; outputLower &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; inputLower&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 constant&quot;&gt;INPUT_RANGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;OUTPUT_RANGE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This code takes input and output ranges, and maps the given values. For example, this usage would give the value 625.&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 function&quot;&gt;mapRange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 625&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;For the portrait, the input value is the center point of each eye, plus or minus some pixel distance. The output range is how much the eyes can translate in pixels. And then the pointer position on the x or y axis gets passed as the value. To get the center point of the eyes while moving them, the eyes are duplicated. The originals don&#39;t move, are transparent, and used for reference.&lt;/p&gt;
&lt;p&gt;Then it&#39;s a case of tying it together and updating the CSS custom property values on the eyes so the eyes can move. A function is bound to the &lt;code&gt;pointermove&lt;/code&gt; event against the &lt;code&gt;window&lt;/code&gt;. As this fires, the bounds of each eye get used to calculate the center points. Then the pointer position is mapped to values that are set as custom property values on the eyes.&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; &lt;span class=&quot;token constant&quot;&gt;RANGE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;interact&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// map a range against the eyes and pass in via custom properties&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE_BOUNDS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE_BOUNDS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CENTERS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;lx&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&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;rx&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&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;ly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LEFT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&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;ry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT_EYE_BOUNDS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CENTERS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapRange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LIMIT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LIMIT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;RANGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RANGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;x&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token constant&quot;&gt;EYES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once the values are passed to CSS, the styles can do what they want with them. The great part here is using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/clamp&quot; rel=&quot;noopener&quot;&gt;CSS &lt;code&gt;clamp()&lt;/code&gt;&lt;/a&gt; to make the behavior different for each eye, so you can make each eye behave differently without touching the JavaScript again.&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;.portrait__eye--mover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; translate 0.2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;.portrait__eye--mover.portrait__eye--left&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-10px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--lx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-4px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ly&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 0.5px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;.portrait__eye--mover.portrait__eye--right&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-4px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--rx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-4px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * 0.5px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ciul3m4cJLWEy9vD6CVx.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/vYrOOGG?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen vYrOOGG by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h3 id=&quot;casting-spells&quot;&gt;Casting spells &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#casting-spells&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you check out page six, do you feel spellbound? This page embraces the design of our fantastic magical fox. If you move your pointer around, you may see a custom cursor trail effect. This uses canvas animation. A &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element sits above the rest of the page content with &lt;code&gt;pointer-events: none&lt;/code&gt;. This means users can still click the content blocks underneath.&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;.wand-canvas&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&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;br /&gt;  &lt;span class=&quot;token property&quot;&gt;pointer-events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Much like how our portrait listens for a &lt;code&gt;pointermove&lt;/code&gt; event on &lt;code&gt;window&lt;/code&gt;, so does our &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element. Yet each time the event fires, we&#39;re creating an object to animate on the &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element. These objects represent shapes used in the cursor trail. They have coordinates and a random hue.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;mapRange&lt;/code&gt; function from earlier is used again, as we can use it to map the pointer delta to &lt;code&gt;size&lt;/code&gt; and &lt;code&gt;rate&lt;/code&gt;. The objects are stored in an array that gets looped over when the objects are drawn to the &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element. The properties for each object tell our &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element where things should be drawn.&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; blocks &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;createBlock&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; movementX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; movementY &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LOWER_SIZE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CANVAS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UPPER_SIZE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CANVAS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.25&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapRange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LOWER_SIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UPPER_SIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movementX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movementY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapRange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LOWER_SIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UPPER_SIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CANVAS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; block &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;hue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;359&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      rate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    blocks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;window&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;pointermove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createBlock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;For drawing to the canvas, a loop is created with &lt;code&gt;requestAnimationFrame&lt;/code&gt;. The cursor trail should only render when the page is in view. We have an &lt;code&gt;IntersectionObserver&lt;/code&gt; that updates and determines which pages are in view. If a page is in view, the objects are rendered as circles on the canvas.&lt;/p&gt;
&lt;p&gt;We then loop over the &lt;code&gt;blocks&lt;/code&gt; array and draw each part of the trail. Each frame reduces the size and alters the position of the object by the &lt;code&gt;rate&lt;/code&gt;. This produces that falling and scaling effect. If the object shrinks completely, the object is removed from the &lt;code&gt;blocks&lt;/code&gt; array.&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;let&lt;/span&gt; wandFrame&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;drawBlocks&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clearRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CANVAS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CANVAS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PAGE_SIX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;className&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;in-view&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; wandFrame&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     blocks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token function&quot;&gt;cancelAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wandFrame&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pointermove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createBlock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;resize&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; b &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; b &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; blocks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; block &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; blocks&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;     ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strokeStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;hsla(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hue&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, 80%, 80%, 0.5)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;     ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;arc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;     ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rate&lt;br /&gt;     block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rate&lt;br /&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       blocks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&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;   wandFrame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;drawBlocks&lt;span 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;If the page goes out of view, event listeners are removed and the animation frame loop is canceled. The &lt;code&gt;blocks&lt;/code&gt; array is also cleared.&lt;/p&gt;
&lt;p&gt;Here&#39;s the cursor trail in action!&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/1v5SAuZIIC0fpxNzfVX1.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/QWxbbQB?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen QWxbbQB by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h2 id=&quot;accessibility-review&quot;&gt;Accessibility review &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#accessibility-review&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s all good creating a fun experience to explore, but it&#39;s no good if it isn&#39;t accessible to users. &lt;a href=&quot;https://twitter.com/argyleink&quot; rel=&quot;noopener&quot;&gt;Adam&lt;/a&gt;&#39;s expertise in this area proved invaluable in getting Chrometober prepared for an accessibility review before release.&lt;/p&gt;
&lt;p&gt;Some of the notable areas covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensuring that the HTML used was semantic. This included things like appropriate landmark elements such as &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; for the book; aso the use of the &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; element for each content block, and &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt; elements where acronyms are introduced. Thinking ahead as the book was built made things more accessible. The use of headings and links makes it easier for a user to navigate. The use of a list for the pages also means the number of pages is announced by assistive technology.&lt;/li&gt;
&lt;li&gt;Ensuring that all images use appropriate &lt;code&gt;alt&lt;/code&gt; attributes. For inline SVGs, the &lt;code&gt;title&lt;/code&gt; element is present where necessary.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;aria&lt;/code&gt; attributes where they improve the experience. The use of &lt;code&gt;aria-label&lt;/code&gt; for pages and their sides communicates to the user which page they are on. The use of &lt;code&gt;aria-describedBy&lt;/code&gt; on the &amp;quot;Read more&amp;quot; links communicates the text of the content block. This removes ambiguity about where the link will take the user.&lt;/li&gt;
&lt;li&gt;On the subject of content blocks, the ability to click the whole card and not only the &amp;quot;Read more&amp;quot; link is available.&lt;/li&gt;
&lt;li&gt;The use of an &lt;code&gt;IntersectionObserver&lt;/code&gt; to track which pages are in view came up earlier. This has many benefits that aren&#39;t just performance related. Pages not in view will have any animation or interaction paused. But these pages also have the &lt;code&gt;inert&lt;/code&gt; attribute applied. This means that users using a screen reader can explore the same content as sighted users. Focus remains within the page that&#39;s in view and users can&#39;t tab to another page.&lt;/li&gt;
&lt;li&gt;Last but not least, we make use of media queries to respect a user&#39;s preference for motion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s a screenshot from the review highlighting some of the measures in place.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of the front page of the Chrometober book. Green outlined boxes are provided around various aspects of the UI, describing the intended accessibility functionality and the user experience outcomes that the page will deliver. For example, header elements have a green box around them, indicating they can be navigated via headline landmarks. Another example is the &amp;lt;main&amp;gt; element is identified as around the whole book, indicating it should be the main landmark for assistive technology users to find. More is outlined in the screenshot.&quot; decoding=&quot;async&quot; height=&quot;465&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/BtC3lPDyNj9DqIg7uT9s.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;img alt=&quot;Screenshot of the Chrometober book open. Green outlined boxes are provided around various aspects of the UI, describing the intended accessibility functionality and the user experience outcomes that the page will deliver. For example, images have alt text. Another example is an accessibility label declaring that pages out of view are inert. More is outlined in the screenshot.&quot; decoding=&quot;async&quot; height=&quot;463&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/ecmrk7v25vNJJC9ENukj.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;what-we-learned&quot;&gt;What we learned &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#what-we-learned&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The motivation behind Chrometober was not only to highlight web content from the community, but was also a way for us to test drive the scroll-linked animations API polyfill that&#39;s in development.&lt;/p&gt;
&lt;p&gt;We set aside a session while on our team summit in New York to test the project and tackle issues that arose. The team&#39;s contribution was invaluable. It was also a great opportunity to list all the things that needed tackling before we could go live.&lt;/p&gt;
&lt;img alt=&quot;CSS, UI, and DevTools team sit around the table in a conference room. Una stands at a whiteboard which is covered in sticky notes. Other team members sit around the table with refreshments and laptops.&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/XZUlK54695r51ACoMRFr.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;For example, testing out the book on devices raised a rendering issue. Our book wouldn&#39;t render as expected on iOS devices. Viewport units size the page, but when a notch was present, it affected the book. The solution was to use &lt;code&gt;viewport-fit=cover&lt;/code&gt; in the &lt;code&gt;meta&lt;/code&gt; viewport:&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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width, initial-scale=1, viewport-fit=cover&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;This session also raised some issues with the API polyfill. &lt;a href=&quot;https://twitter.com/bramus&quot; rel=&quot;noopener&quot;&gt;Bramus&lt;/a&gt; raised these issues in the polyfill repository. He subsequently found solutions to those issues and got them merged into the polyfill. For example, &lt;a href=&quot;https://github.com/flackr/scroll-timeline/pull/84&quot; rel=&quot;noopener&quot;&gt;this pull request&lt;/a&gt; made a performance gain by adding caching to part of the polyfill.&lt;/p&gt;
&lt;img alt=&quot;A screenshot of a demo open in Chrome. The Developer Tools are open and show a baseline performance measurement.&quot; decoding=&quot;async&quot; height=&quot;392&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KqWtVBOnDI4irqSg75fy.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;img alt=&quot;A screenshot of a demo open in Chrome. The Developer Tools are open and show an improved performance measurement.&quot; decoding=&quot;async&quot; height=&quot;392&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/KtNfXA8JbaP3embdPPxK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;thats-it&quot;&gt;That&#39;s it! &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-chrometober/#thats-it&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This has been a real fun project to work on, resulting in a whimsical scrolling experience that highlights amazing content from the community. Not only that, it&#39;s been great for testing the polyfill, as well as providing feedback to the engineering team to help improve the polyfill.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&quot;&quot; loop=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/fNQYmEUY2CSbhPJ8fEnz.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;div style=&quot;height: 450px; 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/PoaqYrR?height=450&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen PoaqYrR by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/chrometober-2022&quot;&gt;Chrometober 2022&lt;/a&gt; is a wrap.&lt;/p&gt;
&lt;p&gt;We hope you enjoyed it! What&#39;s your favorite feature? &lt;a href=&quot;https://twitter.com/jh3yy&quot; rel=&quot;noopener&quot;&gt;Tweet me&lt;/a&gt; and let us know!&lt;/p&gt;
&lt;img alt=&quot;Jhey holding a sticker sheet of the characters from Chrometober.&quot; decoding=&quot;async&quot; height=&quot;601&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/Dyx9FwYgMyNqy1kMGx8Orz6q0qC3/RjZRcgYXbrBiUuI9q2iB.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;You might even be able to grab some stickers from one of the team if you &lt;a href=&quot;https://developer.chrome.com/meet-the-team/&quot; rel=&quot;noopener&quot;&gt;see us at an event&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hero Photo by &lt;a href=&quot;https://unsplash.com/@cazault&quot; rel=&quot;noopener&quot;&gt;David Menidrey&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/pumpkins&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Jhey Tompkins</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>CSS Animated Grid Layouts</title>
      <link href="https://web.dev/css-animated-grid-layouts/"/>
      <updated>2022-10-25T00:00:00Z</updated>
      <id>https://web.dev/css-animated-grid-layouts/</id>
      <content type="text/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 browser engines! &lt;/div&gt;&lt;/aside&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;chrome 107, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        107
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 66, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        66
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;edge 107, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        107
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        16
      &lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
&lt;h2 id=&quot;value-interpolation-in-css&quot;&gt;Value Interpolation in CSS &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/css-animated-grid-layouts/#value-interpolation-in-css&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In CSS you can smoothly transition properties from one value to the other using the &lt;code&gt;transition&lt;/code&gt; property.&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;#target&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; opacity ease-in-out 0.25s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;#target:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The rendering engine will automatically detect the type of the targeted property’s value, and use that information to smoothly transition to the new value.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transitioning &lt;code&gt;opacity&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;?
That’s a numerical interpolation.&lt;/li&gt;
&lt;li&gt;Transitioning &lt;code&gt;background-color&lt;/code&gt; from &lt;code&gt;white&lt;/code&gt; to &lt;code&gt;black&lt;/code&gt;?
Fade between the source and target colors.&lt;/li&gt;
&lt;li&gt;Transitioning &lt;code&gt;width&lt;/code&gt;?
Interpolate numerically, converting units along the way if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same applies to CSS animations, where the browser will do value interpolation between keyframes.&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 Custom Properties, &lt;a href=&quot;https://web.dev/at-property&quot;&gt;use &lt;code&gt;@property&lt;/code&gt;&lt;/a&gt; to indicate which type they are. That way the browser knows how to transition from one value to the other. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;interpolating-grid-template-columns-and-grid-template-rows&quot;&gt;Interpolating &lt;code&gt;grid-template-columns&lt;/code&gt; and &lt;code&gt;grid-template-rows&lt;/code&gt; &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/css-animated-grid-layouts/#interpolating-grid-template-columns-and-grid-template-rows&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to our contributors at Microsoft, Chrome–as of version 107–is able to interpolate &lt;code&gt;grid-template-columns&lt;/code&gt; and &lt;code&gt;grid-template-rows&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;Grid layouts can smoothly transition between states, instead of snapping at the halfway point of an animation or transition.&lt;/p&gt;
&lt;p&gt;In the demo below a grid is showing several avatars. To conserve space, the avatars are laid out on top of each other by limiting the width of each column using &lt;code&gt;grid-template-columns&lt;/code&gt;. On hover, each column is given more space.&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;.avatars&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.35em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;grid-auto-flow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; column&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 2em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; all ease-in-out 0.25s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;.avatars:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 4em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;With the &lt;code&gt;transition&lt;/code&gt; property in place, the grid smoothly interpolates between values.&lt;/p&gt;
&lt;div 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://codepen.io/web-dot-dev/embed/XWqVowx?height=480&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen XWqVowx by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;The effect also applies to animations that change the &lt;code&gt;grid-template-columns&lt;/code&gt; or &lt;code&gt;grid-template-rows&lt;/code&gt; values.&lt;/p&gt;
&lt;div style=&quot;height: 780px; 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/jOxRdzw?height=780&amp;theme-id=light&amp;default-tab=result&amp;editable=true&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;Pen jOxRdzw by web-dot-dev on Codepen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@namzo&quot; rel=&quot;noopener&quot;&gt;Ernest Ojeh&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/rTpPZD9PAk4&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</content>
      <author>
          <name>Bramus</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Building a tooltip component</title>
      <link href="https://web.dev/building-a-tooltip-component/"/>
      <updated>2022-10-25T00:00:00Z</updated>
      <id>https://web.dev/building-a-tooltip-component/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;In this post I want to share my thoughts on how to build a color-adaptive and accessible &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; custom element. &lt;a href=&quot;https://gui-challenges.web.app/tooltips/dist/&quot; rel=&quot;noopener&quot;&gt;Try the
demo&lt;/a&gt; and &lt;a href=&quot;https://github.com/argyleink/gui-challenges&quot; rel=&quot;noopener&quot;&gt;view the
source&lt;/a&gt;!&lt;/p&gt;
&lt;style&gt;
  .auto-aspect {
    aspect-ratio: auto;
  }
&lt;/style&gt;
&lt;figure data-size=&quot;full&quot;&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/vS06HQ1YTsbMKSFTIPl2iogUQP73/pLo4ykDKsCiyDexUb208.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    A tooltip is shown working across a variety of examples and color schemes
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you prefer video, here&#39;s a YouTube version of this post:&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;Y5EIC_UyPME&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A tooltip is a non-modal, non-blocking, non-interactive overlay containing
supplemental information to user interfaces. It is hidden by default and becomes
unhidden when an associated element is hovered or focused. A tooltip can&#39;t be
selected or interacted with directly. Tooltips are not replacements for labels
or other high value information, a user should be able to fully complete their
task without a tooltip.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;245&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/b2K0zdHds4yQQNST7DUj.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Do: always label your inputs.&lt;br /&gt;
    Don&#39;t: rely on tooltips instead of labels
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;toggletip-vs-tooltip&quot;&gt;Toggletip vs Tooltip &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#toggletip-vs-tooltip&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like many components, there are varying descriptions of what a tooltip is, for
example in
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/tooltip_role&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/&quot; rel=&quot;noopener&quot;&gt;WAI ARIA&lt;/a&gt;, &lt;a href=&quot;https://sarahmhigley.com/writing/tooltips-in-wcag-21/&quot; rel=&quot;noopener&quot;&gt;Sarah
Higley&lt;/a&gt;, and &lt;a href=&quot;https://inclusive-components.design/tooltips-toggletips/&quot; rel=&quot;noopener&quot;&gt;Inclusive
Components&lt;/a&gt;. I like
the separation between tooltips and toggletips. A tooltip should contain
non-interactive supplemental information, while a toggletip can contain
interactivity and important information. The primary reason for the divide is
accessibility, how are users expected to navigate to the popup and have access
to the information and buttons within. Toggletips get complex quickly.&lt;/p&gt;
&lt;p&gt;Here&#39;s a video of a toggletip from the &lt;a href=&quot;https://designcember.com/&quot; rel=&quot;noopener&quot;&gt;Designcember&lt;/a&gt;
site; an overlay with interactivity that a user can pin open and explore, then
close with light dismiss or the escape key:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/DM7qi0GUBZQGpR2qvMst.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This GUI Challenge went the route of a tooltip, looking to do almost everything
with CSS, and here&#39;s how to build it.&lt;/p&gt;
&lt;h2 id=&quot;markup&quot;&gt;Markup &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#markup&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I chose to use a custom element &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt;. Authors don&#39;t need to make custom
elements into web components if they don&#39;t want to. The browser will treat
&lt;code&gt;&amp;lt;foo-bar&amp;gt;&lt;/code&gt; just like a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. You could think of a custom element like a
classname with less specificity. There&#39;s no JavaScript involved.&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;tool-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A tooltip&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&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;This is like a div with some text inside. We can tie into the accessibility tree
of capable screen readers by adding &lt;code&gt;[role=&amp;quot;tooltip&amp;quot;]&lt;/code&gt;.&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;tool-tip&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;tooltip&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;A tooltip&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&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;Now, to screen readers, it&#39;s recognized as a tooltip. See in the following
example how the first link element has a recognized tooltip element in its tree
and the second does not? The second one doesn&#39;t have the role. In the styles
section we&#39;ll improve upon this tree view.&lt;/p&gt;
&lt;img alt=&quot;A screenshot of Chrome DevTools Accessibility Tree representing the HTML. Shows a link with text &amp;#x27;top ; Has tooltip: Hey, a tooltip!&amp;#x27; that&amp;#x27;s focusable. Inside of it is static text of &amp;#x27;top&amp;#x27; and a tooltip element.&quot; decoding=&quot;async&quot; height=&quot;268&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/yFjZc6VXnJhXPBKk6nGA.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Next we need the tooltip to not be focusable. If a screen reader doesn&#39;t
understand the tooltip role it will allow users to focus the &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; to
read the contents, and the user experience doesn&#39;t need this. Screen readers
will append the content to the parent element and as such, it doesn&#39;t need focus
to be made accessible. Here we can use &lt;code&gt;inert&lt;/code&gt; to ensure no users will
accidentally find this tooltip content in their tab flow:&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;inert&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;tooltip&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;A tooltip&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&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;img alt=&quot;Another screenshot of Chrome DevTools Accessibility Tree, this time the tooltip element is missing.&quot; decoding=&quot;async&quot; height=&quot;77&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/sNBvSvyOyfJQdu2viQHs.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;I then chose to use attributes as the interface to specify the position of the
tooltip. By default all the &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt;s will assume a &amp;quot;top&amp;quot; position, but the
position can be customized on an element by adding &lt;code&gt;tip-position&lt;/code&gt;:&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;tool-tip&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;tooltip&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tip-position&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;right &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;A tooltip&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&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;img alt=&quot;A screenshot of a link with a tooltip to the right saying &amp;#x27;A tooltip&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;155&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/TMXICYtLqsuCEUrOROOn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;I tend to use attributes instead of classes for things like this so that the
&lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; can&#39;t have multiple positions assigned to it at the same time.
There can be only one or none.&lt;/p&gt;
&lt;p&gt;Finally, place &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; elements inside of the element you wish to provide a
tooltip for. Here I share the &lt;code&gt;alt&lt;/code&gt; text with sighted users by placing an image
and a &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; inside of a
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/picture&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;&lt;/a&gt;
element:&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;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;The GUI Challenges skull logo&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;100&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;tool-tip&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;tooltip&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tip-position&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;bottom&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;    The &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;GUI Challenges&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; skull logo&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;img alt=&quot;A screenshot of an image with a tooltip that says &amp;#x27;The GUI Challenges skull logo&amp;#x27;.&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/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/JeKL6O5gpZTaqdAdY20w.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Here I place a &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; inside of an
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/abbr&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt;&lt;/a&gt;
element:&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  The &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;abbr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;HTML &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;tool-tip&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;tooltip&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tip-position&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;top&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;Hyper Text Markup Language&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;tool-tip&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;abbr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; abbr element.&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img alt=&quot;A screenshot of a paragraph with the acronym HTML underlined and a tooltip above it saying &amp;#x27;Hyper Text Markup Language&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;250&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 512px) 512px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/AfXJazViIAf8ONlI3AxF.png?auto=format&amp;w=1024 1024w&quot; width=&quot;512&quot; /&gt;
&lt;h2 id=&quot;accessibility&quot;&gt;Accessibility &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since I&#39;ve chosen to build tooltips and not toggletips, this section is much
simpler. First, let me outline what our desired user experience:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In constrained spaces or cluttered interfaces, hide supplemental messages.&lt;/li&gt;
&lt;li&gt;When a user hovers, focuses or uses touch to interact with an element, reveal
the message.&lt;/li&gt;
&lt;li&gt;When hover, focus or touch ends, hide the message again.&lt;/li&gt;
&lt;li&gt;Lastly, ensure any motion is reduced if a user has specified a preference for
reduced motion.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our goal is on demand supplemental messaging. A sighted mouse or keyboard user can hover to reveal the message, reading it with their eyes. A non-sighted screen reader user can focus to reveal the message, audibly receiving it through their tool.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;&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/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/UysCSNx4AhGBPeStZ3CU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Screenshot of MacOS VoiceOver reading a link with a tooltip
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the previous section we covered the accessibility tree, the tooltip role and
inert, what&#39;s left is to test it and verify the user experience appropriately
reveals the tooltip message to the user. Upon testing, it&#39;s unclear as to which
part of the audible message is a tooltip. It can be seen while debugging in the
accessibility tree too, the link text of &amp;quot;top&amp;quot; is run together, without
hesitation, with &amp;quot;Look, tooltips!&amp;quot;. The screen reader doesn&#39;t break or identify
the text as tooltip content.&lt;/p&gt;
&lt;img alt=&quot;A screenshot of the Chrome DevTools Accessibility Tree where the link text says &amp;#x27;top Hey, a tooltip!&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;106&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/wfn1xsgRMUuQxG4SXfT4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Add a screen reader only pseudo-element to the &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; and we can add our
own prompt text for non-sighted users.&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;&amp;amp;::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;; Has tooltip: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Below you can see the updated accessibility tree, which now has a semicolon
after the link text and a prompt for the tooltip &amp;quot;Has tooltip: &amp;quot;.&lt;/p&gt;
&lt;img alt=&quot;An updated screenshot of the Chrome DevTools Accessibility Tree where the link text has improved phrasing, &amp;#x27;top ; Has tooltip: Hey, a tooltip!&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;82&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/cLTxacpxlsqNQtO2fTi4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Now, when a screen reader user focuses the link, it says &amp;quot;top&amp;quot; and takes a small
pause, then announces &amp;quot;has tooltip: look, tooltips&amp;quot;. This gives a screen reader
user a couple nice UX hints. The hesitation gives a nice separation between the
link text and the tooltip. Plus, when &amp;quot;has tooltip&amp;quot; is announced, a screen
reader user can easily cancel it if they&#39;ve already heard it before. It&#39;s very
reminiscent to hovering and unhovering quickly, as you&#39;ve already seen the
supplemental message. This felt like nice UX parity.&lt;/p&gt;
&lt;h2 id=&quot;styles&quot;&gt;Styles &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#styles&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt; element will be a child of the element it&#39;s representing
supplemental messaging for, so let&#39;s first start with the essentials for the
overlay effect. Take it out of document flow with &lt;code&gt;position absolute&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;tool-tip&lt;/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;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If the parent is not a stacking context, the tooltip will position itself to the
nearest one that is, which isn&#39;t what we want. There&#39;s a new selector on the
block that can help, &lt;a href=&quot;https://developer.chrome.com/blog/has-m105/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;:has()&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;browser-compat&quot;&gt;
      &lt;span class=&quot;browser-compat__label&quot;&gt;Browser support:&lt;/span&gt;
      &lt;span class=&quot;browser-compat__items&quot;&gt;&lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        105
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;firefox 103, Behind a flag&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;flag&quot;&gt;
        ⚑
      &lt;/span&gt;
      &lt;span class=&quot;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;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        105
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
          &lt;span class=&quot;visually-hidden&quot;&gt;safari 15.4, Supported&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class=&quot;browser-compat__version&quot; data-compat=&quot;yes&quot;&gt;
        15.4
      &lt;/span&gt;
      &lt;/span&gt;&lt;span class=&quot;browser-compat__link&quot;&gt;
        &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/:has#browser_compatibility&quot; target=&quot;_blank&quot;&gt;
          Source
        &lt;/a&gt;
      &lt;/span&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;:has(&gt; tool-tip)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Don&#39;t worry too much about the browser support. First, remember these tooltips
are supplementary. If they don&#39;t work it should be fine. Second, in the
JavaScript section we&#39;ll deploy a script to polyfill the functionality we need
for browsers without &lt;code&gt;:has()&lt;/code&gt; support.&lt;/p&gt;
&lt;p&gt;Next, let&#39;s make the tooltips non-interactive so they don’t steal pointer events
from their parent element:&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  …&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;pointer-events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;user-select&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then, hide the tooltip with opacity so we can transition the tooltip with a
crossfade:&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;:has(&gt; tool-tip):is(:hover, :focus-visible, :active) &gt; tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&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;&lt;/a&gt; and &lt;code&gt;:has()&lt;/code&gt; do
the heavy lifting here, making &lt;code&gt;tool-tip&lt;/code&gt; containing parent elements aware of
user interactivity as to toggle the visibility of a child tooltip. Mouse users
can hover, keyboard and screen reader users can focus, and touch users can tap.&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; I think the reality of this tooltip solution is that touch users get the worst experience, as they need to hold their finger over the element to see the tooltip. Really ensure these tooltips are supplemental information. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;With the show and hide overlay working for sighted users, it&#39;s time to add some
styles for theming, positioning and adding the triangle shape to the bubble. The
following styles begin using custom properties, building upon where we are so
far but also adding shadows, typography and colors so it looks like a floating
tooltip:&lt;/p&gt;
&lt;img alt=&quot;A screenshot of the tooltip in dark mode, floating over the link &amp;#x27;block-start&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;272&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 796px) 796px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ofzjTXNlID2kGJsL4MYo.png?auto=format&amp;w=1592 1592w&quot; width=&quot;796&quot; /&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_p-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_p-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .75ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_triangle-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 7px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 20%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_shadow-alpha&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;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_bottom-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;conic-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from -30deg at bottom&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #000 1deg 60deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 61deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; bottom / 100% 50% no-repeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_top-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;conic-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from 150deg at top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #000 1deg 60deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 61deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; top / 100% 50% no-repeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_right-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;conic-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from -120deg at right&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #000 1deg 60deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 61deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; right / 50% 100% no-repeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_left-tip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;conic-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;from 60deg at left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #000 1deg 60deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 61deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; left / 50% 100% no-repeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;pointer-events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;user-select&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;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&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;--_x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; opacity .2s ease&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transform .2s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; max-content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;max-inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 25ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&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; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;--_p-block&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;--_p-inline&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CanvasText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;will-change&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; filter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;drop-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 3px 3px &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 0% / &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_shadow-alpha&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;drop-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 12px 12px &lt;span class=&quot;token function&quot;&gt;hsl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0 0% 0% / &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_shadow-alpha&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;/* create a stacking context for elements with &gt; tool-tips */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;:has(&gt; tool-tip)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* when those parent elements have focus, hover, etc */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;:has(&gt; tool-tip):is(:hover, :focus-visible, :active) &gt; tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;/* prepend some prose for screen readers only */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;; Has tooltip: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* tooltip shape is a pseudo element so we can cast a shadow */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;mask&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;--_tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;/* top tooltip styles */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:is(&lt;br /&gt;  [tip-position=&quot;top&quot;],&lt;br /&gt;  [tip-position=&quot;block-start&quot;],&lt;br /&gt;  :not([tip-position]),&lt;br /&gt;  [tip-position=&quot;bottom&quot;],&lt;br /&gt;  [tip-position=&quot;block-end&quot;]&lt;br /&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;theme-adjustments&quot;&gt;Theme adjustments &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#theme-adjustments&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The tooltip only has a few colors to manage as the text color is inherited from
the page via the system keyword &lt;code&gt;CanvasText&lt;/code&gt;. Also, since we&#39;ve made custom
properties to store the values, we can update only those custom properties and
let the theme handle the rest:&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;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_shadow-alpha&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 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;A side by side screenshot of the light and dark versions of the tooltip.&quot; decoding=&quot;async&quot; height=&quot;153&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/mdoUK4pOHiyf4jcgpACG.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;For the light theme, we adapt the background to white and make the shadows much
less strong by adjusting their opacity.&lt;/p&gt;
&lt;h3 id=&quot;right-to-left&quot;&gt;Right to left &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#right-to-left&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to support right to left reading modes, a custom property will store
the value of the document direction into a value of -1 or 1 respectively.&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--isRTL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:dir(rtl)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--isRTL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This can be used to assist in positioning the tooltip:&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;tool-tip[tip-position=&quot;top&quot;])&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50% * &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--isRTL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;As well as assist in where the triangle is:&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;tool-tip[tip-position=&quot;right&quot;]::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_left-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;tool-tip[tip-position=&quot;right&quot;]:dir(rtl)::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_right-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;Lastly, can also be used for logical transforms on &lt;code&gt;translateX()&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 property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--isRTL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; * -3px * -1&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;tooltip-positioning&quot;&gt;Tooltip positioning &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#tooltip-positioning&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Position the tooltip logically with the &lt;code&gt;inset-block&lt;/code&gt; or &lt;code&gt;inset-inline&lt;/code&gt;
properties to handle both the physical and logical tooltip positions. The
following code shows how each of the four positions are styled for both
left-to-right and right-to-left directions.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/Qi9AZrjpX4s9Nzoe1yZX.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h4 id=&quot;top-and-block-start-alignment&quot;&gt;Top and block-start alignment &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#top-and-block-start-alignment&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;img alt=&quot;A screenshot showing the placement difference between left-to-right top position and right-to-left top position.&quot; decoding=&quot;async&quot; height=&quot;191&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/XPtm4jrENpk3wt7p1e4V.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;tool-tip:is([tip-position=&quot;top&quot;], [tip-position=&quot;block-start&quot;], :not([tip-position]))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-start&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; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_p-block&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50% * &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--isRTL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;tool-tip:is([tip-position=&quot;top&quot;], [tip-position=&quot;block-start&quot;], :not([tip-position]))::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_bottom-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-block-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_triangle-size&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 property&quot;&gt;border-block-end&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;right-and-inline-end-alignment&quot;&gt;Right and inline-end alignment &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#right-and-inline-end-alignment&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;img alt=&quot;A screenshot showing the placement difference between left-to-right right position and right-to-left inline-end position.&quot; decoding=&quot;async&quot; height=&quot;421&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/HyTs2tuKcPbmHnH3BVor.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;tool-tip:is([tip-position=&quot;right&quot;], [tip-position=&quot;inline-end&quot;])&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_p-inline&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&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; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_y&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:is([tip-position=&quot;right&quot;], [tip-position=&quot;inline-end&quot;])::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_left-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_triangle-size&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 property&quot;&gt;border-inline-start&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:is([tip-position=&quot;right&quot;], [tip-position=&quot;inline-end&quot;]):dir(rtl)::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_right-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;h4 id=&quot;bottom-and-block-end-alignment&quot;&gt;Bottom and block-end alignment &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#bottom-and-block-end-alignment&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;img alt=&quot;A screenshot showing the placement difference between left-to-right bottom position and right-to-left block-end position.&quot; decoding=&quot;async&quot; height=&quot;216&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/CgSlkA2Styscf9rDRAnf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;tool-tip:is([tip-position=&quot;bottom&quot;], [tip-position=&quot;block-end&quot;])&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-start&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-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_p-block&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;50% * &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--isRTL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;tool-tip:is([tip-position=&quot;bottom&quot;], [tip-position=&quot;block-end&quot;])::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_top-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-block-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_triangle-size&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 property&quot;&gt;border-block-start&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;left-and-inline-start-alignment&quot;&gt;Left and inline-start alignment &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#left-and-inline-start-alignment&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;img alt=&quot;A screenshot showing the placement difference between left-to-right left position and right-to-left inline-start position.&quot; decoding=&quot;async&quot; height=&quot;486&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/ASyNnVtZ8bp9VuwFgfH2.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;tool-tip:is([tip-position=&quot;left&quot;], [tip-position=&quot;inline-start&quot;])&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100% + &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_p-inline&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&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; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_y&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:is([tip-position=&quot;left&quot;], [tip-position=&quot;inline-start&quot;])::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_right-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_triangle-size&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 property&quot;&gt;border-inline-end&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;--_triangle-size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; solid transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;tool-tip:is([tip-position=&quot;left&quot;], [tip-position=&quot;inline-start&quot;]):dir(rtl)::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_tip&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;--_left-tip&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;animation&quot;&gt;Animation &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#animation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far we&#39;ve only toggled the visibility of the tooltip. In this section we&#39;ll
first animate opacity for all users, as it&#39;s a generally safe reduced motion
transition. Then we&#39;ll animate the transform position so the tooltip appears to
slide out from the parent element.&lt;/p&gt;
&lt;h3 id=&quot;a-safe-and-meaningful-default-transition&quot;&gt;A safe and meaningful default transition &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#a-safe-and-meaningful-default-transition&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Style the tooltip element to transition opacity and transform, like this:&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;tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&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;--_x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; opacity .2s ease&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transform .2s 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 selector&quot;&gt;:has(&gt; tool-tip):is(:hover, :focus-visible, :active) &gt; tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition-delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 200ms&lt;span 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;&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/vS06HQ1YTsbMKSFTIPl2iogUQP73/zCibybxd4947z1qLnGEP.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;adding-motion-to-the-transition&quot;&gt;Adding motion to the transition &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#adding-motion-to-the-transition&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For each of the sides a tooltip can appear on, if the user is ok with motion,
slightly position the translateX property by giving it a small distance to
travel from:&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;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;:has(&gt; tool-tip:is([tip-position=&quot;top&quot;], [tip-position=&quot;block-start&quot;], :not([tip-position]))):not(:hover):not(:focus-visible):not(:active) tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;:has(&gt; tool-tip:is([tip-position=&quot;right&quot;], [tip-position=&quot;inline-end&quot;])):not(:hover):not(:focus-visible):not(:active) tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -3px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;:has(&gt; tool-tip:is([tip-position=&quot;bottom&quot;], [tip-position=&quot;block-end&quot;])):not(:hover):not(:focus-visible):not(:active) tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -3px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;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;:has(&gt; tool-tip:is([tip-position=&quot;left&quot;], [tip-position=&quot;inline-start&quot;])):not(:hover):not(:focus-visible):not(:active) tool-tip&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px&lt;span class=&quot;token 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;&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/vS06HQ1YTsbMKSFTIPl2iogUQP73/OUglbz54FT80hEZY5ouw.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Notice this is setting the &amp;quot;out&amp;quot; state, as the &amp;quot;in&amp;quot; state is at &lt;code&gt;translateX(0)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;javascript&quot;&gt;JavaScript &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my opinion, the JavaScript is optional. This is because none of these
tooltips should be required reading to accomplish a task in your UI. So if the
tooltips completely fail, it should be no big deal. This also means we can treat
the tooltips as progressively enhanced. Eventually all browsers will support
&lt;code&gt;:has()&lt;/code&gt; and this script can completely go away.&lt;/p&gt;
&lt;p&gt;The polyfill script does two things, and does so only if the browser doesn&#39;t
support &lt;code&gt;:has()&lt;/code&gt;. First, check for &lt;code&gt;:has()&lt;/code&gt; support:&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token 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;supports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;selector(:has(*))&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// do work&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;Next, find the parent elements of &lt;code&gt;&amp;lt;tool-tip&amp;gt;&lt;/code&gt;s and give them a classname to
work 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 keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token 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;supports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;selector(:has(*))&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;tool-tip&#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;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tooltip&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;&lt;br /&gt;    tooltip&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentNode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;has_tool-tip&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next, inject a set of styles that use that classname, simulating the &lt;code&gt;:has()&lt;/code&gt;
selector for the exact same behavior:&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token 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;supports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;selector(:has(*))&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;tool-tip&#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;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tooltip&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;&lt;br /&gt;    tooltip&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentNode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;has_tool-tip&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; styles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;style&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;    .has_tool-tip {&lt;br /&gt;      position: relative;&lt;br /&gt;    }&lt;br /&gt;    .has_tool-tip:is(:hover, :focus-visible, :active) &gt; tool-tip {&lt;br /&gt;      opacity: 1;&lt;br /&gt;      transition-delay: 200ms;&lt;br /&gt;    }&lt;br /&gt;  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;styles&lt;span 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;That&#39;s it, now all browsers will happily show the tooltips if &lt;code&gt;:has()&lt;/code&gt; is not
supported.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you know how I did it, how would you‽ 🙂 I&#39;m really looking forward to
the
&lt;a href=&quot;https://developer.chrome.com/blog/pop-ups-theyre-making-a-resurgence/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;popup&lt;/code&gt;&lt;/a&gt;
API for making toggletips easier, &lt;a href=&quot;https://developer.chrome.com/blog/what-is-the-top-layer/&quot; rel=&quot;noopener&quot;&gt;top
layer&lt;/a&gt; for no z-index
battles, and the
&lt;a href=&quot;https://twitter.com/jh3yy/status/1563206768049926144?s=20&amp;amp;t=MiEcoMGyRHr5eS_CtWLsmg&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;anchor&lt;/code&gt;&lt;/a&gt;
API for positioning things in the window better. Until then, I&#39;ll be making
tooltips.&lt;/p&gt;
&lt;p&gt;Let&#39;s diversify our approaches and learn all the ways to build on the web.&lt;/p&gt;
&lt;p&gt;Create a demo, &lt;a href=&quot;https://twitter.com/argyleink&quot; rel=&quot;noopener&quot;&gt;tweet me&lt;/a&gt; links, and I&#39;ll add it
to the community remixes section below!&lt;/p&gt;
&lt;h2 id=&quot;community-remixes&quot;&gt;Community remixes &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#community-remixes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Nothing to see here yet.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-tooltip-component/#resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/argyleink/gui-challenges/tree/main/tooltips&quot; rel=&quot;noopener&quot;&gt;Source code&lt;/a&gt; on Github&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Adam Argyle</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Building a Better Web - Part 1: A faster YouTube on web</title>
      <link href="https://web.dev/better-youtube-web-part1/"/>
      <updated>2022-10-20T00:00:00Z</updated>
      <id>https://web.dev/better-youtube-web-part1/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;The Chrome team often talks about &amp;quot;building a &lt;em&gt;better&lt;/em&gt; web&amp;quot;, but what does that
mean? Web experiences should be &lt;a href=&quot;https://web.dev/why-speed-matters/&quot;&gt;fast&lt;/a&gt;,
&lt;a href=&quot;https://web.dev/accessibility/&quot;&gt;accessible&lt;/a&gt;, and use &lt;a href=&quot;https://web.dev/reliable/&quot;&gt;device
capabilities&lt;/a&gt; in the moment when users need it most.
&lt;a href=&quot;https://en.wikipedia.org/wiki/Eating_your_own_dog_food&quot; rel=&quot;noopener&quot;&gt;Dogfooding&lt;/a&gt; is part of Google&#39;s culture, so the Chrome team has partnered with
YouTube to share lessons learned along the way in a new series called, &amp;quot;Building
a better web&amp;quot;. The first part of the series will dive into how YouTube built a
faster web experience.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;PageSpeed Insights showing the Chrome UX Report data for YouTube Mobile Web passing the Core Web Vitals.&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hIcVf8Pob6DaLrmNjdNX.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    The YouTube for mobile web Watch page passing the &lt;a href=&quot;https://web.dev/vitals&quot;&gt;Core Web Vitals&lt;/a&gt; thresholds.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;building-a-faster-web&quot;&gt;Building a faster web &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/better-youtube-web-part1/#building-a-faster-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At YouTube, &lt;em&gt;performance&lt;/em&gt; relates to how fast videos and other content—such as
recommendations and comments—load on web pages. Performance is also measured by how quickly YouTube
responds to user interactions such as search, player control, likes, and shares.&lt;/p&gt;
&lt;p&gt;Growing developing markets, such as Brazil, India, and Indonesia are important
for YouTube mobile web. Because many users in these regions have slower devices
and limited network bandwidth, ensuring a fast and seamless experience is a
critical goal.&lt;/p&gt;
&lt;p&gt;To provide an inclusive experience for all users, YouTube set out to improve
performance metrics such as &lt;a href=&quot;https://web.dev/vitals&quot;&gt;Core Web Vitals&lt;/a&gt; through lazy-loading and code
modernization.&lt;/p&gt;
&lt;h3 id=&quot;improving-core-web-vitals&quot;&gt;Improving Core Web Vitals &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/better-youtube-web-part1/#improving-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To identify areas of improvement, the YouTube team used the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience Report (CrUX)&lt;/a&gt; to see how real users were experiencing video watch and search result pages on
mobile in &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#field-data&quot;&gt;the
field&lt;/a&gt;. They
realized their Core Web Vitals metrics had a lot of room for improvement, with
their &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt; metric clocking in
at 4-6 seconds in some cases. This was substantially higher than their target of
2.5 seconds.&lt;/p&gt;
&lt;img alt=&quot;Charts of FCP and LCP showing YouTube Watch page pass rates as well as the YouTube origin.&quot; decoding=&quot;async&quot; height=&quot;285&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/uy6hO7M60rRw3bTfXTCH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To identify areas for improvement, they turned to
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; to audit
the YouTube watch pages, revealing a low Lighthouse
(&lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#lab-data&quot;&gt;lab&lt;/a&gt;) score with a
First Contentful Paint (FCP) of 3.5 seconds and a LCP of 8.5 seconds.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Lighthouse Report for YouTube Mobile.&quot; decoding=&quot;async&quot; height=&quot;518&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PeCzGyBCTcY63B5Nft1a.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Chrome sets a target of 1.8s for FCP and 2.5s for LCP as a gold standard. The FCP and LCP were clearly in the yellow and red at 3.5s and 8.5s, respectively.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To optimize FCP and LCP, the YouTube team dove into several experiments,
resulting in two big discoveries.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The first discovery was that they could improve performance by moving the HTML for the Video Player above the script that makes the Video Player interactive. Lab tests indicated that this could improve both FCP and LCP from 4.4 seconds to 1.1 seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The second discovery was that LCP only &lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;considers&lt;/a&gt; &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element poster images and not frames from the video stream itself. YouTube has traditionally optimized for the fastest time until the video starts playing, so to improve LCP the team started also optimizing how quickly they could deliver their poster image. They experimented with a few variations of poster images and picked the one that scored the best in user testing. As a result of this work, both FCP and LCP showed marked improvement, with field LCP improving from 4.6 seconds to 2.0 seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img alt=&quot;Watch Page LCP Experiment for mobile web showing control, experiment A (image thumbnail) and experiment B (black thumbnail)&quot; decoding=&quot;async&quot; height=&quot;514&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wJKAgsXRqrexp9yDJ4T1.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    In the lab, we observed an improvement in FCP and LCP from 4.4s to 1.1s after this change landed. Experiment A: Using the actual video thumbnail works well on pages where the video starts out paused, but for auto-play video pages like the watch page it performed poorly in user studies. It also resulted in a drop in active users. Experiment B: Using a solid black poster image showed the best results in user studies. Users found the transition from solid black to the first frame of the video to be a less-jarring experience for autoplay videos. 
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img alt=&quot;The black thumbnail was deployed in production for all mobile web users July 2021 showing marked improvement in FCP and LCP, as seen in the above RUM analysis.&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/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wGjBH4sMWoZEbRon6gBS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Black thumbnail was deployed in production for all mobile web users July 2021 showing marked improvement in FCP and LCP, as seen in the above RUM analysis.
  &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; While bringing these optimizations to all platforms, YouTube also took advantage of the new &lt;a href=&quot;https://web.dev/priority-hints/&quot;&gt;Priority Hints&lt;/a&gt; &lt;code&gt;fetchpriority&lt;/code&gt; attribute, which we use with &lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt; to prioritize discovering and loading the poster image early:  &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;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&amp;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;&amp;quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&amp;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;&amp;quot;&lt;/span&gt;poster.jpg&lt;span class=&quot;token punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;While these optimizations did improve LCP, the team felt that the current definition of the LCP metric wasn&#39;t fully capturing, from the user&#39;s perspective, when the &amp;quot;main content&amp;quot; of the page had loaded—which is the goal of LCP.&lt;/p&gt;
&lt;p&gt;To address these concerns, members of the YouTube team partnered with members of the Chrome team to explore ways that the LCP metric could be improved to address their use case. After considering the feasibility and impact of a few options, the teams landed on a &lt;a href=&quot;https://github.com/w3c/largest-contentful-paint/issues/85&quot; rel=&quot;noopener&quot;&gt;proposal&lt;/a&gt; to consider the paint time of the first frame of a video element as an LCP candidate.&lt;/p&gt;
&lt;p&gt;Once this change lands in Chrome, the YouTube team is excited to continue their work optimizing for LCP. And the updated version of the metric will mean these optimizations will have a more direct impact on real-user experiences.&lt;/p&gt;
&lt;h3 id=&quot;modularization-with-lazy-loading&quot;&gt;Modularization with lazy loading &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/better-youtube-web-part1/#modularization-with-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;YouTube pages contained many modules that were eagerly loaded. To optimize how
50+ components were rendered, the team built a component to JS module map that
would tell the client which modules to load. By marking components as lazy, the
JS modules would load later, reducing the initial load time of the page and the
amount of unused Javascript sent to the client.&lt;/p&gt;
&lt;p&gt;However, after lazy loading was implemented, the team noticed a waterfall effect
that lazy loaded components and their dependencies would load at suboptimal
times.&lt;/p&gt;
&lt;p&gt;To solve this problem, the team determined the minimal set of components needed
in a view and batched them in a single network request. The results were
improved page speed, reduced JavaScript parse time, and, ultimately, better
initial rendering times.&lt;/p&gt;
&lt;h3 id=&quot;state-management-across-components&quot;&gt;State-management across components &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/better-youtube-web-part1/#state-management-across-components&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;YouTube was experiencing performance issues due to its player controls,
especially on older devices. Code analysis showed that the player, which allows
users to control features such as playback speed and progress, had become
over-componentized over time.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;YouTube player and controls visualized&quot; decoding=&quot;async&quot; height=&quot;300&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qh9N7ZdkxylN1vYOOdUO.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    The YouTube video player allows users to control playback speed, follow progress, skip sections, and others. When a user taps on a particular control, the change in the state must be communicated to other controls e.g. a user tap on the progress bar must be shared to controls such as play-head, subtitles etc.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Each progress bar touch-move event triggered two
extra style recalculations and took 21.17 ms during performance test runs in the lab. As new controls were added over time, the pattern of decentralized control would often cause circular dependencies and memory leaks, negatively impacting watch page performance.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;21.17 ms event shown on the Performance timeline.&quot; decoding=&quot;async&quot; height=&quot;202&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vCTMilflEoDnkw1p8EuU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Chrome DevTools with a 4 times CPU slow-down performance run. 
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To fix the issues due to decentralized control, the team updated the player UI
to synchronize all updates, essentially refactoring the player to one top-level
component that would pass down data to its children. This ensured only one UI
update (render) cycle for any state change, eliminating chained updates. The new
player progress bar touch-move event has no style recalculations during its
JavaScript execution and now only requires 25% the time of the old player.&lt;/p&gt;
&lt;img alt=&quot;Reduced time in events shown on the performance timeline.&quot; decoding=&quot;async&quot; height=&quot;90&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/E1EbOYuT2q7mDqfmR1zz.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This code modernization also resulted in additional performance improvements
such as improved watch load times on old devices, fewer abandoned playbacks, and
a reduced number of non-fatal errors.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/better-youtube-web-part1/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a result of YouTube&#39;s investment in performance, watch pages load much faster with 76% of YouTube&#39;s mobile website URLs now passing Core Web Vitals metric thresholds in the field. On desktop, lab LCP for the watch page was reduced from approximately 4.6 seconds to 1.6 seconds. Interaction and rendering performance of the site, especially on the YouTube video player, are seeing up to 75% less time spent in JavaScript execution than before.&lt;/p&gt;
&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 24 24&quot; height=&quot;24&quot; width=&quot;24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Check&quot;&gt;   &lt;path d=&quot;M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Success&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; 76% of YouTube&#39;s mobile web URLs now pass the Core Web Vitals metrics, with improvements to business metrics like watch time as a result. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Improvements to the performance of YouTube web over the last year have also improved business metrics, including watch time and daily active users. Based on the success of these efforts, we plan to continue exploring even more ways to optimize in the future.&lt;/p&gt;
&lt;p&gt;In part two of this series, &amp;quot;Building an accessible web&amp;quot;, you’ll read how YouTube made their website more accessible for screen-reader users.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With special thanks to Gilberto Cocchi, Lauren Usui, Benji Bear, Bo Aye, Bogdan Balas, Kenny Tran, Matthew Smith, Phil Harnish, Leena Sahoni, Jeremy Wagner, Philip Walton, Harleen Batra and both the YouTube and Chrome teams for their contributions to this work.&lt;/em&gt;&lt;/p&gt;
</content>
      <author>
          <name>Addy Osmani</name>
        </author><author>
          <name>Sriram Krishnan</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Create a passkey for passwordless logins</title>
      <link href="https://web.dev/passkey-registration/"/>
      <updated>2022-10-12T00:00:00Z</updated>
      <id>https://web.dev/passkey-registration/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;Using &lt;a href=&quot;https://developers.google.com/identity/passkeys&quot; rel=&quot;noopener&quot;&gt;passkeys&lt;/a&gt; instead of
passwords is a great way for websites to make their user accounts safer,
simpler, easier to use and passwordless. With a passkey, a user can sign in to a
website or an app just by using their fingerprint, face or device PIN.&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 learn basic concepts of passkeys, check out &lt;a href=&quot;https://developers.google.com/identity/passkeys&quot;&gt;Passwordless login with passkeys&lt;/a&gt; first.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;A passkey has to be created, associated with a user account and have its public key be stored on your server before a user can sign in with it.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How it works &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#how-it-works&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A user can be asked to create a passkey in one of the following situations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a user signs in using a password, or a passkey from another device (that is,
the
&lt;a href=&quot;https://web.dev/passkey-form-autofill/#:~:text=authenticationattachment&quot;&gt;&lt;code&gt;authenticatorAttachment&lt;/code&gt;&lt;/a&gt;
is &lt;code&gt;cross-platform&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;On a dedicated page where users can manage their passkeys.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&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/YLflGBAPWecgtKJLqCJHSzHqe2J2/2gY9wppN8tivRRWDH8gV.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;To create a passkey, you use &lt;a href=&quot;https://w3c.github.io/webauthn/&quot; rel=&quot;noopener&quot;&gt;the WebAuthn
API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The four components of the passkey registration flow are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Your backend server that holds the accounts database storing the
public key and other metadata about the passkey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Your frontend which communicates with the browser and sends
fetch requests to the backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser&lt;/strong&gt;: The user&#39;s browser which is running your Javascript.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticator&lt;/strong&gt;: The user&#39;s authenticator which creates and stores the
passkey. This may be on the same device as the browser (for example, when using
Windows Hello) or on another device, like a phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;screenshot&quot;&gt;
  &lt;img alt=&quot;Passkey registration diagram&quot; decoding=&quot;async&quot; height=&quot;258&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vmxdOrHbR2kW17Ipv6hk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The journey to add a new passkey to an existing user account is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user signs in to the website.&lt;/li&gt;
&lt;li&gt;Once the user is signed in, they request to create a passkey on the
frontend, for example, by pressing a &amp;quot;Create a passkey&amp;quot; button.&lt;/li&gt;
&lt;li&gt;The frontend requests information from the
backend to create a passkey, such as user
information, a challenge, and the credential IDs to exclude.&lt;/li&gt;
&lt;li&gt;The frontend calls &lt;code&gt;navigator.credentials.create()&lt;/code&gt; to create a passkey.
This call returns a promise.&lt;/li&gt;
&lt;li&gt;A passkey is created after the user consents using the device&#39;s screen lock.
The promise is resolved and a public key credential is returned to the
frontend.&lt;/li&gt;
&lt;li&gt;The frontend sends the public key credential to the backend and stores the
credential ID and the public key associated with the user account for future
authentications.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;compatibilities&quot;&gt;Compatibilities &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#compatibilities&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebAuthn is supported by most browsers, but there are small gaps. Refer to
&lt;a href=&quot;https://passkeys.dev/device-support/&quot; rel=&quot;noopener&quot;&gt;Device Support - passkeys.dev&lt;/a&gt; to learn
what combination of browsers and an operating systems support creating a
passkey.&lt;/p&gt;
&lt;h2 id=&quot;create-a-new-passkey&quot;&gt;Create a new passkey &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#create-a-new-passkey&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how a frontend should operate upon a request to create a new passkey.&lt;/p&gt;
&lt;h3 id=&quot;feature-detection&quot;&gt;Feature detection &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#feature-detection&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before displaying a &amp;quot;Create a new passkey&amp;quot; button, check if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The browser supports WebAuthn.&lt;/li&gt;
&lt;li&gt;The device supports a platform authenticator (can create a passkey and
authenticate with the passkey).&lt;/li&gt;
&lt;li&gt;The browser supports &lt;a href=&quot;https://web.dev/passkey-form-autofill/&quot;&gt;WebAuthn conditional UI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&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 comment&quot;&gt;// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// `​​isConditionalMediationAvailable` means the feature detection is usable.  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PublicKeyCredential &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;br /&gt;    PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isUserVerifyingPlatformAuthenticatorAvailable &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;br /&gt;    PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;​​isConditionalMediationAvailable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Check if user verifying platform authenticator is available.  &lt;/span&gt;&lt;br /&gt;  Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;  &lt;br /&gt;    PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isUserVerifyingPlatformAuthenticatorAvailable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;    PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;​​isConditionalMediationAvailable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;every&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; r &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Display &quot;Create a new passkey&quot; button  &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Until all the conditions have been met, passkeys will not be supported on this browser.
The &amp;quot;Create a new passkey&amp;quot; button shouldn&#39;t be displayed until then.&lt;/p&gt;
&lt;h3 id=&quot;fetch-important-information-from-the-backend&quot;&gt;Fetch important information from the backend &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#fetch-important-information-from-the-backend&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the user clicks the button, fetch important information to call
&lt;code&gt;navigator.credentials.create()&lt;/code&gt; from the backend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-challenge&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;challenge&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
A server-generated challenge in ArrayBuffer for this registration. This is
required but unused during registration unless doing
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Web_Authentication_API/Attestation_and_Assertion&quot; rel=&quot;noopener&quot;&gt;attestation&lt;/a&gt;—an
advanced topic not covered here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;user.id&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
A user&#39;s unique ID. This value must be an ArrayBuffer which does not include
personally identifying information, for example, e-mail addresses or usernames. A
random, 16-byte value generated per account will work well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;user.name&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
This field should hold a unique identifier for the account that the user will
recognise, like their email address or username. This will be displayed in the
account selector. (If using a username, use the same value as in password
authentication.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;user.displayName&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
This field is an optional, more user-friendly name for the account. It need not be unique
and could be the user&#39;s chosen name. If your site does not have a suitable
value to include here, pass an empty string. This may be displayed on the
account selector depending on the browser.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-excludecredentials&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;excludeCredentials&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
Prevents registering the same device by providing a list of already registered
credential IDs. The
&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialdescriptor-transports&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;transports&lt;/code&gt;&lt;/a&gt;
member, if provided, should contain the result of calling
&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-gettransports&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;getTransports()&lt;/code&gt;&lt;/a&gt;
during the registration of each credential.&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;  ArrayBuffer values transferred from the server such as &lt;code&gt;challenge&lt;/code&gt;, &lt;code&gt;user.id&lt;/code&gt; and credential &lt;code&gt;id&lt;/code&gt; for &lt;code&gt;excludeCredentials&lt;/code&gt; need to be encoded on transmission. Don&#39;t forget to decode them on the frontend before passing to the WebAuthn API call. We recommend using Base64URL encode.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;call-webauthn-api-to-create-a-passkey&quot;&gt;Call WebAuthn API to create a passkey &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#call-webauthn-api-to-create-a-passkey&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Call &lt;code&gt;navigator.credentials.create()&lt;/code&gt; to create a new passkey. The API returns
a promise, waiting for the user&#39;s interaction displaying a modal dialog.&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; publicKeyCredentialCreationOptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;challenge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token operator&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;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;rp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Example&quot;&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;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token operator&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;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;&quot;john78&quot;&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;displayName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;pubKeyCredParams&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;alg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public-key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;alg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;257&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public-key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;excludeCredentials&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token operator&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;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;public-key&#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;transports&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;internal&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;authenticatorSelection&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;authenticatorAttachment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;platform&quot;&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;requireResidentKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; credential &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;credentials&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&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;publicKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; publicKeyCredentialCreationOptions  &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Encode and send the credential to the server for verification.  &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The parameters not explained above are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialrpentity-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rp.id&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An RP ID is a domain and a website can specify either its domain or a
registrable suffix. For example, if an RP&#39;s origin is
&lt;code&gt;https://login.example.com:1337&lt;/code&gt;, the RP ID can be either
&lt;code&gt;login.example.com&lt;/code&gt; or &lt;code&gt;example.com&lt;/code&gt;. If the RP ID is specified as
&lt;code&gt;example.com&lt;/code&gt;, the user can authenticate on &lt;code&gt;login.example.com&lt;/code&gt; or on any
subdomains on &lt;code&gt;example.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rp.name&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
The RP&#39;s name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-pubkeycredparams&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;pubKeyCredParams&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
This field specifies the RP&#39;s supported public-key algorithms. We recommend setting
it to &lt;code&gt;[{alg: -7, type: &amp;quot;public-key&amp;quot;},{alg: -257, type: &amp;quot;public-key&amp;quot;}]&lt;/code&gt;.
This specifies support for ECDSA with P-256 and RSA PKCS#1 and supporting
these gives complete coverage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorselectioncriteria-authenticatorattachment&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;authenticatorSelection.authenticatorAttachment&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
Set it to &amp;quot;platform&amp;quot;. This indicates that we want an authenticator that is
embedded into the platform device, and the user will not be prompted to insert
e.g. a USB security key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorselectioncriteria-residentkey&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;authenticatorSelection.requireResidentKey&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
Set it to a boolean &amp;quot;true&amp;quot;. A discoverable credential (resident key)
stores user information to the passkey and lets users select the account upon
authentication.&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;  Note: Some browsers don&#39;t require any parameters on &lt;code&gt;authenticatorSelection&lt;/code&gt; to create a passkey, but others may. We recommend specifying those parameters explicitly.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;send-the-returned-public-key-credential-to-the-backend&quot;&gt;Send the returned public key credential to the backend &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#send-the-returned-public-key-credential-to-the-backend&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After the user consents using the device&#39;s screen lock, a passkey is created and
the promise is resolved returning a
&lt;a href=&quot;https://w3c.github.io/webauthn/#authenticatorattestationresponse&quot; rel=&quot;noopener&quot;&gt;PublicKeyCredential&lt;/a&gt;
object to the frontend.&lt;/p&gt;
&lt;p&gt;The promise can be rejected for different reasons. You can handle these errors by checking the &lt;code&gt;Error&lt;/code&gt; object&#39;s &lt;code&gt;name&lt;/code&gt; property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;InvalidStateError&lt;/code&gt;&lt;/strong&gt;: A passkey already exists on the device. No error
dialog will be shown to the user and the site should not treat this as an
error—the user wanted the local device registered and it is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NotAllowedError&lt;/code&gt;&lt;/strong&gt;: The user has canceled the operation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other exceptions&lt;/strong&gt;: Something unexpected happened. The browser shows an
error dialog to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The public key credential object contains the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#credential-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: A Base64URL encoded
ID of the created passkey. This ID helps the browser to determine whether a
matching passkey is in the device upon authentication. This value needs to be stored
in the database on the backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#credential-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rawId&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: An ArrayBuffer
version of the credential ID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#client-data&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.clientDataJSON&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer encoded client data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#attestation-object&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.attestationObject&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer encoded attestation object. This contains important information
such as an RP ID, flags and a public key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#enumdef-authenticatorattachment&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;authenticatorAttachment&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
Returns &lt;code&gt;&amp;quot;platform&amp;quot;&lt;/code&gt; when this credential is created on a passkey capable
device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;type&lt;/code&gt;&lt;/strong&gt;: This field is always set to &lt;code&gt;&amp;quot;public-key&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use a library to handle the public key credential object on the backend,
we recommend sending the entire object to the backend after encoding it
partially with base64url.&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;  Optionally, the &lt;code&gt;response&lt;/code&gt; member of the credential - an &lt;a href=&quot;https://w3c.github.io/webauthn/#iface-authenticatorattestationresponse&quot;&gt;&lt;code&gt;AuthenticatorAttestationResponse&lt;/code&gt;&lt;/a&gt; — provides &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-gettransports&quot;&gt;&lt;code&gt;getTransports()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-getpublickey&quot;&gt;&lt;code&gt;getPublicKey()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-getauthenticatordata&quot;&gt;&lt;code&gt;getAuthenticatorData()&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-getpublickey&quot;&gt;&lt;code&gt;getPublicKeyAlgorithm()&lt;/code&gt;&lt;/a&gt; functions to retrieve elements of the credential.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;save-the-credential&quot;&gt;Save the credential &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#save-the-credential&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Upon receiving the public key credential on the backend, pass it to the FIDO
library to process the object.&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 recommend using a server-side library or a solution instead of writing your own code to process a public-key credential. Check out &lt;a href=&quot;https://github.com/herrjemand/awesome-webauthn&quot;&gt;open-source libraries &lt;/a&gt; to process public-key credentials.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;You can then store the information retrieved from the credential to the database for
future use. The following list includes some typical properties to save:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Credential ID (Primary key)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User ID&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public key&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The public-key credential also includes the following information
that you may want to save in the database:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#backup-eligibility&quot; rel=&quot;noopener&quot;&gt;Backup Eligibility
flag&lt;/a&gt;&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt; if the
device is eligible for passkey synchronization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#backup-state&quot; rel=&quot;noopener&quot;&gt;Backup State flag&lt;/a&gt;&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt;
if the created passkey is actually set to be synchronized.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#enumdef-authenticatortransport&quot; rel=&quot;noopener&quot;&gt;Transports&lt;/a&gt;&lt;/strong&gt;:
A list of transports the device supports: &lt;code&gt;&amp;quot;internal&amp;quot;&lt;/code&gt; means the device
supports a passkey, &lt;code&gt;&amp;quot;hybrid&amp;quot;&lt;/code&gt; means it also supports &lt;a href=&quot;https://developers.google.com/identity/passkeys/use-cases#sign-in-with-a-phone&quot; rel=&quot;noopener&quot;&gt;authentication on
another
device&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To authenticate the user, read &lt;a href=&quot;https://web.dev/passkey-form-autofill&quot;&gt;Sign in with a passkey through form
autofill&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-registration/#resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/passkey-form-autofill&quot;&gt;Sign in with a passkey through form autofill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.imperialviolet.org/2022/09/22/passkeys.html&quot; rel=&quot;noopener&quot;&gt;Passkeys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/authenticationservices/authenticating_a_user_through_a_web_service&quot; rel=&quot;noopener&quot;&gt;Apple document: Authenticating a User Through a Web
Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/identity/passkeys/&quot; rel=&quot;noopener&quot;&gt;Google document: Passwordless login with
passkeys&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Eiji Kitamura</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Sign in with a passkey through form autofill</title>
      <link href="https://web.dev/passkey-form-autofill/"/>
      <updated>2022-10-12T00:00:00Z</updated>
      <id>https://web.dev/passkey-form-autofill/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://developers.google.com/identity/passkeys&quot; rel=&quot;noopener&quot;&gt;Passkeys&lt;/a&gt; replace passwords
and make user accounts on the web safer, simpler, easier to use. However, the
transition from password-based to passkey-based authentication can complicate
the user experience. Using form autofill to suggest passkeys can help
create a unified experience.&lt;/p&gt;
&lt;h2 id=&quot;why-use-form-autofill-to-sign-in-with-a-passkey&quot;&gt;Why use form autofill to sign-in with a passkey? &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#why-use-form-autofill-to-sign-in-with-a-passkey&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With a passkey, a user can sign in to a website just by using fingerprint, face,
or device PIN.&lt;/p&gt;
&lt;p&gt;Ideally, there would be no password users and the authentication flow
could be as simple as a single sign-in button. When the user taps the button, an
account selector dialog pops up, the user can pick an account, unlock the screen
to verify and sign in.&lt;/p&gt;
&lt;p&gt;However, the transition from password to passkey-based authentication can be
challenging. As users switch to passkeys, there will still be those who use
passwords and websites will need to accommodate both types of users. Users
themselves should not be expected to remember on which sites they&#39;ve switched to
passkeys, so asking users to select which method to use up front would be poor
UX.&lt;/p&gt;
&lt;p&gt;Passkeys are also a new technology. Explaining them and making sure users are
comfortable using them can be a challenge for websites. We can rely on familiar
user experiences for autofilling passwords to solve both problems.&lt;/p&gt;
&lt;h2 id=&quot;conditional-ui&quot;&gt;Conditional UI &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#conditional-ui&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To build an efficient user experience for both passkey and password users, you
can include passkeys in autofill suggestions. This is called &lt;a href=&quot;https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI&quot; rel=&quot;noopener&quot;&gt;conditional
UI&lt;/a&gt; and
it&#39;s a part of &lt;a href=&quot;https://w3c.github.io/webauthn/&quot; rel=&quot;noopener&quot;&gt;the WebAuthn standard&lt;/a&gt;.&lt;/p&gt;
&lt;figure&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/YLflGBAPWecgtKJLqCJHSzHqe2J2/ZaxgMtkOh5CX2B1ZT9gd.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;As soon as the user taps on the username input field, an autofill suggestion
dialog pops up which highlights the stored passkeys along with password autofill
suggestions. The user can then choose an account and use the device screen lock
to sign in.&lt;/p&gt;
&lt;p&gt;This way, users can sign in to your website with the existing form as if nothing
has changed, but with &lt;a href=&quot;https://developers.google.com/identity/passkeys#security-considerations&quot; rel=&quot;noopener&quot;&gt;the added security benefit of
passkeys&lt;/a&gt;
if they have one.&lt;/p&gt;
&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 24 24&quot; height=&quot;24&quot; width=&quot;24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Check&quot;&gt;   &lt;path d=&quot;M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Success&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt;  When a user signs in with a password, consider using that opportunity to offer them to &lt;a href=&quot;https://web.dev/passkey-registration&quot;&gt;create a passkey&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How it works &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#how-it-works&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To authenticate with a passkey, you use &lt;a href=&quot;https://w3c.github.io/webauthn/&quot; rel=&quot;noopener&quot;&gt;the WebAuthn
API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The four components in a passkey authentication flow are:
the user:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Your backend server that holds the accounts database storing the
public key and other metadata about the passkey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Your frontend which communicates with the browser and sends
fetch requests to the backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser&lt;/strong&gt;: The user&#39;s browser which is running your Javascript.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticator&lt;/strong&gt;: The user&#39;s authenticator which creates and stores the
passkey. This may be on the same device as the browser (e.g. when using
Windows Hello) or on another device, like a phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;screenshot&quot;&gt;
  &lt;img alt=&quot;Passkey authentication diagram&quot; decoding=&quot;async&quot; height=&quot;254&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/YLflGBAPWecgtKJLqCJHSzHqe2J2/vAwnMiLi7U1spDopYg2Q.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;As soon as a user lands on the frontend, it requests a challenge from the
backend to authenticate with a passkey and calls
&lt;code&gt;navigator.credentials.get()&lt;/code&gt; to initiate authenticating with a passkey.
This returns a &lt;code&gt;Promise&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When the user puts the cursor in the sign-in field, the browser displays a
password autofill dialog including passkeys. An authentication dialog appears
if the user selects a passkey.&lt;/li&gt;
&lt;li&gt;After the user verifies their identity using the device&#39;s screen lock, the
promise is resolved and a public key credential is returned to the frontend.&lt;/li&gt;
&lt;li&gt;The frontend sends the public key credential to the backend. The backend
verifies the signature against the matched account&#39;s public key in the
database. If it succeeds, the user is signed in.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#prerequisites&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Conditional WebAuthn UI is publicly supported in Safari on iOS 16, iPadOS 16 and
macOS Ventura. It&#39;s also available on Chrome on Android, macOS and Windows 11
22H2.&lt;/p&gt;
&lt;h2 id=&quot;authenticate-with-a-passkey-through-form-autofill&quot;&gt;Authenticate with a passkey through form autofill &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#authenticate-with-a-passkey-through-form-autofill&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a user wants to sign in, you can make a conditional WebAuthn &lt;code&gt;get&lt;/code&gt; call
to indicate that passkeys may be included in autofill suggestions. A conditional
call to &lt;a href=&quot;https://w3c.github.io/webauthn/&quot; rel=&quot;noopener&quot;&gt;WebAuthn&lt;/a&gt;&#39;s
&lt;code&gt;navigator.credentials.get()&lt;/code&gt; API does not show UI and remains pending until
the user picks an account to sign-in with from the autofill suggestions. If the
user picks a passkey the browser will resolve the promise with a credential
rather than filling in the sign-in form. It&#39;s then the page&#39;s responsibility to
sign the user in.&lt;/p&gt;
&lt;h3 id=&quot;annotate-form-input-field&quot;&gt;Annotate form input field &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#annotate-form-input-field&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add an &lt;code&gt;autocomplete&lt;/code&gt; attribute to the username &lt;code&gt;input&lt;/code&gt; field, if needed.
Append &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;webauthn&lt;/code&gt; as its tokens to let it suggest passkeys.&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;username&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;username webauthn&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&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;h3 id=&quot;feature-detection&quot;&gt;Feature detection &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#feature-detection&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before invoking a conditional WebAuthn API call, check if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The browser supports WebAuthn.&lt;/li&gt;
&lt;li&gt;The browser supports WebAuthn conditional UI.&lt;/li&gt;
&lt;/ul&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 comment&quot;&gt;// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PublicKeyCredential &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;br /&gt;    PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;​​isConditionalMediationAvailable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Check if conditional mediation is available.  &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isCMA &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; PublicKeyCredential&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;​​isConditionalMediationAvailable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isCMA&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Call WebAuthn authentication  &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;h3 id=&quot;fetch-a-challenge-from-the-rp-server&quot;&gt;Fetch a challenge from the RP server &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#fetch-a-challenge-from-the-rp-server&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Fetch a challenge from the RP server that is required to call
&lt;code&gt;navigator.credentials.get()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-challenge&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;challenge&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
A server-generated challenge in an ArrayBuffer. This is required to prevent
replay attacks. Make sure to generate a new challenge on every sign-in attempt
and disregard it after a certain duration or after a sign-in attempt fails to
validate. Consider it like a CSRF token.&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;  ArrayBuffer values transferred from the server such as &lt;code&gt;challenge&lt;/code&gt;, &lt;code&gt;user.id&lt;/code&gt; and credential &lt;code&gt;id&lt;/code&gt; for &lt;code&gt;excludeCredentials&lt;/code&gt; need to be encoded on transmission. Make sure to decode them on the RP frontend before passing the values to the WebAuthn API call. We recommend using Base64URL encode.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;call-webauthn-api-with-the-conditional-flag-to-authenticate-the-user&quot;&gt;Call WebAuthn API with the &lt;code&gt;conditional&lt;/code&gt; flag to authenticate the user &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#call-webauthn-api-with-the-conditional-flag-to-authenticate-the-user&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Call &lt;code&gt;navigator.credentials.get()&lt;/code&gt; to start waiting for the user authentication.&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 comment&quot;&gt;// To abort a WebAuthn call, instantiate an `AbortController`.  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AbortController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; publicKeyCredentialRequestOptions &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 comment&quot;&gt;// Server generated challenge  &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;challenge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token 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 comment&quot;&gt;// The same RP ID as used during registration  &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;rpId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;example.com&#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;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; credential &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;credentials&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; publicKeyCredentialRequestOptions&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; abortController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;signal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Specify &#39;conditional&#39; to activate conditional UI  &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;mediation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;conditional&#39;&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;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialrequestoptions-rpid&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rpId&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An RP ID is a domain and a website can specify either its domain or a
registrable suffix. This value must match the rp.id used when the passkey was
created.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to specify &lt;code&gt;mediation: &#39;conditional&#39;&lt;/code&gt; to make the request conditional.&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 WebAuthn call here will be pending and the promise won&#39;t be resolved until the user interacts with the autofill input element and completes the authentication flow. The RP frontend can use &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/AbortController&quot;&gt;&lt;code&gt;AbortController&lt;/code&gt;&lt;/a&gt; to abort the WebAuthn call.  &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;send-the-returned-public-key-credential-to-the-rp-server&quot;&gt;Send the returned public key credential to the RP server &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#send-the-returned-public-key-credential-to-the-rp-server&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After the user selects an account and consents using the device&#39;s screen lock,
the promise is resolved returning a
&lt;a href=&quot;https://w3c.github.io/webauthn/#authenticatorassertionresponse&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;PublicKeyCredential&lt;/code&gt;&lt;/a&gt;
object to the RP frontend.&lt;/p&gt;
&lt;p&gt;A promise can be rejected due to several different reasons. You need to handle the errors accordingly,
depending on the &lt;code&gt;Error&lt;/code&gt; object&#39;s &lt;code&gt;name&lt;/code&gt; property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NotAllowedError&lt;/code&gt;&lt;/strong&gt;: The user has canceled the operation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other exceptions&lt;/strong&gt;: Something unexpected happened. The browser shows an
error dialog to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The public key credential object contains the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#credential-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: The
base64url encoded ID of the authenticated passkey credential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#credential-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rawId&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: An
ArrayBuffer version of the credential ID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#client-data&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.clientDataJSON&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer of client data. This field contains information such as the challenge
and the origin that the RP server will need to verify.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-authenticatordata&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.authenticatorData&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer of authenticator data. This field contains information such as the RP
ID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-signature&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.signature&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer of the signature. This value is the core of the credential and needs
to be verified on the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-userhandle&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;response.userHandle&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
An ArrayBuffer that contained the user ID that was set at creation time. This
value can be used, instead of the credential ID, if the server needs to pick
the ID values that it uses, or if the backend wishes to avoid creating an
index on credential IDs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/webauthn/#enumdef-authenticatorattachment&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;authenticatorAttachment&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:
Returns &lt;code&gt;platform&lt;/code&gt; when this credential came from the local device.
Otherwise &lt;code&gt;cross-platform&lt;/code&gt;, notably when &lt;a href=&quot;https://developers.google.com/identity/passkeys/use-cases#sign-in-with-a-phone&quot; rel=&quot;noopener&quot;&gt;the user used a phone to sign
in&lt;/a&gt;.
If the user needed to use a phone to sign-in, consider prompting them to
&lt;a href=&quot;https://web.dev/passkey-registration&quot;&gt;create a passkey&lt;/a&gt; on the local device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;type&lt;/code&gt;&lt;/strong&gt;: This field is always set to &lt;code&gt;&amp;quot;public-key&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use a library to handle the public-key credential object on the RP
server, we recommend that you send the entire object to the server after encoding it
partially with base64url.&lt;/p&gt;
&lt;h3 id=&quot;verify-the-signature&quot;&gt;Verify the signature &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#verify-the-signature&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you receive the public key credential on the server, pass it to the FIDO
library to process the object.&lt;/p&gt;
&lt;p&gt;Look up the matching credential ID with the
&lt;a href=&quot;https://w3c.github.io/webauthn/#credential-id&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;id&lt;/code&gt;&lt;/a&gt; property (If you need to
determine the user account, use the
&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-userhandle&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;userHandle&lt;/code&gt;&lt;/a&gt;
property which is the &lt;code&gt;user.id&lt;/code&gt; you specified when creating the credential). See
if the credential&#39;s
&lt;a href=&quot;https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-signature&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;signature&lt;/code&gt;&lt;/a&gt;
can be verified with the stored public key. To do so, we recommend using a
server side library or a solution instead of writing your own code. &lt;a href=&quot;https://github.com/herrjemand/awesome-webauthn&quot; rel=&quot;noopener&quot;&gt;You can
find open source libraries in the awesome-webauth GitHub
repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the credential is verified with a matching public key, sign the user in.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/passkey-form-autofill/#resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/passkey-registration/&quot;&gt;Create a passkey for passwordless logins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.imperialviolet.org/2022/09/22/passkeys.html&quot; rel=&quot;noopener&quot;&gt;Passkeys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/authenticationservices/authenticating_a_user_through_a_web_service&quot; rel=&quot;noopener&quot;&gt;Apple document: Authenticating a User Through a Web
Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/identity/passkeys/&quot; rel=&quot;noopener&quot;&gt;Google document: Passwordless login with
passkeys&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Eiji Kitamura</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>New patterns for amazing apps</title>
      <link href="https://web.dev/new-patterns-for-amazing-apps/"/>
      <updated>2022-10-10T00:00:00Z</updated>
      <id>https://web.dev/new-patterns-for-amazing-apps/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;No matter what you build—be it a next generation video editing app, an addictive word game, or a
future online social networking app—you will always find yourself in need of a few basic building
blocks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The video editing app will probably allow the user to &lt;em&gt;save&lt;/em&gt; the edited video.&lt;/li&gt;
&lt;li&gt;Your game will maybe allow the user to &lt;em&gt;share&lt;/em&gt; game progress with friends.&lt;/li&gt;
&lt;li&gt;An online social networking app will highly likely allow the user to &lt;em&gt;paste&lt;/em&gt; images into a post.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;no-universal-way-to-realize-these-patterns&quot;&gt;No universal way to realize these patterns &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#no-universal-way-to-realize-these-patterns&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These were just a couple of examples of such patterns, and there are many more. But all of these
have one thing in common: there is no universal way to realize them.&lt;/p&gt;
&lt;h3 id=&quot;sharing-progress&quot;&gt;Sharing progress &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#sharing-progress&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For example, not all browsers implement the &lt;a href=&quot;https://web.dev/web-share/&quot;&gt;Web Share API&lt;/a&gt;, so in some cases you will
have to fall back to a different approach, like
&lt;a href=&quot;https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/guides/web-intent&quot; rel=&quot;noopener&quot;&gt;Twitter&#39;s Web Intents&lt;/a&gt;,
or copying to the clipboard, which is the
&lt;a href=&quot;https://twitter.com/powerlanguish/status/1471493886031773707&quot; rel=&quot;noopener&quot;&gt;approach&lt;/a&gt; chosen in
&lt;a href=&quot;https://www.nytimes.com/games/wordle/index.html&quot; rel=&quot;noopener&quot;&gt;Wordle&lt;/a&gt; when the Web Share API isn&#39;t implemented.
Phew, barely got this one:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Wordle 471 6/6&lt;br /&gt;&lt;br /&gt;⬛⬛⬛⬛🟨&lt;br /&gt;🟩⬛⬛⬛🟨&lt;br /&gt;🟩🟩🟩⬛⬛&lt;br /&gt;🟩🟩🟩⬛⬛&lt;br /&gt;🟩🟩🟩🟩⬛&lt;br /&gt;🟩🟩🟩🟩🟩&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;saving-files&quot;&gt;Saving files &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#saving-files&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to saving, the go-to approach is to use the
&lt;a href=&quot;https://web.dev/file-system-access/&quot;&gt;File System Access API&lt;/a&gt;, so you end up with a &lt;code&gt;FileSystemFileHandle&lt;/code&gt;, which
allows you to implement a true &lt;a href=&quot;https://web.dev/excalidraw-and-fugu/#saving-files&quot;&gt;save, edit, save flow&lt;/a&gt;. The next
best thing is to fall back to a classic &lt;code&gt;&amp;lt;a download&amp;gt;&lt;/code&gt;, which likewise lets the user save data, but
has the downside of creating new files on each download, so they end up with &lt;code&gt;my-video.mp4&lt;/code&gt;,
&lt;code&gt;my-video (1).mp4&lt;/code&gt;, &lt;code&gt;my-video (2).mp4&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h3 id=&quot;pasting-images&quot;&gt;Pasting images &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#pasting-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To conclude the introductory examples, not all browsers support pasting images into a web app, so
you can fall back to using the Drag and Drop API or showing a file picker, which is not as elegant as
the &lt;a href=&quot;https://web.dev/async-clipboard&quot;&gt;Async Clipboard API&lt;/a&gt;, but at least it works.&lt;/p&gt;
&lt;h2 id=&quot;the-new-patterns&quot;&gt;The new patterns &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#the-new-patterns&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With this out of the way, the new pattern sections are:&lt;/p&gt;
&lt;h3 id=&quot;clipboard-patterns&quot;&gt;Clipboard patterns &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#clipboard-patterns&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/patterns/clipboard/&quot;&gt;Clipboard patterns&lt;/a&gt; for everything concerned with the system clipboard like
copying and pasting of all sorts of things.&lt;/p&gt;
&lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;200&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/eWdb4ici0H9p8tueeUUG.svg&quot; width=&quot;200&quot; /&gt;
&lt;h3 id=&quot;files-patterns&quot;&gt;Files patterns &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#files-patterns&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/patterns/files/&quot;&gt;Files patterns&lt;/a&gt; for everything concerned with files and directories; be it
saving, opening, dragging and dropping, receiving or sharing.&lt;/p&gt;
&lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;200&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/Smch2ZFw5PxkiQZPkl3v.svg&quot; width=&quot;200&quot; /&gt;
&lt;h3 id=&quot;advanced-apps-patterns&quot;&gt;Advanced apps patterns &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#advanced-apps-patterns&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/patterns/advanced-apps/&quot;&gt;Advanced apps patterns&lt;/a&gt; for everything concerned with advanced app
features like providing app shortcuts, periodically syncing data in the background, showing app
badges, and many more.&lt;/p&gt;
&lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;200&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/Yyuu9Wob0ix4z2jgBY1S.svg&quot; width=&quot;200&quot; /&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hope these patterns will help you build amazing apps, and I&#39;m looking forward to your feedback!
You can provide feedback by tweeting at &lt;a href=&quot;https://twitter.com/ChromiumDev&quot; rel=&quot;noopener&quot;&gt;@ChromiumDev&lt;/a&gt; or
&lt;a href=&quot;https://github.com/GoogleChrome/web.dev/issues/new/choose&quot; rel=&quot;noopener&quot;&gt;filing an Issue&lt;/a&gt;. In both cases, tag
&lt;code&gt;@tomayac&lt;/code&gt; to make sure I see it.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/new-patterns-for-amazing-apps/#acknowledgements&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m grateful to &lt;a href=&quot;https://github.com/jpmedley&quot; rel=&quot;noopener&quot;&gt;Joe Medley&lt;/a&gt; for his help with reviewing and editing
the patterns. Thanks to &lt;a href=&quot;https://github.com/petele&quot; rel=&quot;noopener&quot;&gt;Pete LePage&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/devnook&quot; rel=&quot;noopener&quot;&gt;Ewa Gasperowicz&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/rachelandrew&quot; rel=&quot;noopener&quot;&gt;Rachel Andrew&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/kenpascal/&quot; rel=&quot;noopener&quot;&gt;Ken Pascal&lt;/a&gt;,
and &lt;a href=&quot;https://twitter.com/matthiasrohmer&quot; rel=&quot;noopener&quot;&gt;Matthias Rohmer&lt;/a&gt;
for all their technical and organizational support and
encouragements to land this. The entire patterns project would not have been possible without the
help of the authors of the individual patterns, namely
&lt;a href=&quot;https://www.harrytheo.com/&quot; rel=&quot;noopener&quot;&gt;Harry Theodoulou&lt;/a&gt;, &lt;a href=&quot;https://web.dev/authors/conwayt/&quot;&gt;Tony Conway&lt;/a&gt;,
&lt;a href=&quot;https://web.dev/new-patterns-for-amazing-apps/authors/pliao/&quot;&gt;Palances Liao&lt;/a&gt;, &lt;a href=&quot;https://web.dev/authors/chuijun/&quot;&gt;Cecilia Cong&lt;/a&gt;,
&lt;a href=&quot;https://github.com/beaufortfrancois&quot; rel=&quot;noopener&quot;&gt;François Beaufort&lt;/a&gt;, and
&lt;a href=&quot;https://github.com/jpmedley&quot; rel=&quot;noopener&quot;&gt;Joe Medley&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
          <name>Thomas Steiner</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Community highlight: Melanie Sumner</title>
      <link href="https://web.dev/community-highlight-melanie/"/>
      <updated>2022-10-06T00:00:00Z</updated>
      <id>https://web.dev/community-highlight-melanie/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;&lt;em&gt;This post highlights a community expert, as a part of &lt;a href=&quot;https://web.dev/learn/accessibility/&quot;&gt;Learn Accessibility!&lt;/a&gt;&lt;/em&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; Read some recent articles by Melanie on &lt;a href=&quot;https://melsumner.github.io/accessibility-testing&quot;&gt;her process for accessibility testing&lt;/a&gt; and &lt;a href=&quot;https://melsumner.github.io/getting-started-with-accessibility&quot;&gt;getting started with accessibility&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Alexandra White&lt;/strong&gt;: Thanks for joining me! Who you are and what you do?&lt;/p&gt;
&lt;figure data-float=&quot;right&quot;&gt;
&lt;img alt=&quot;Melanie Sumner&amp;#x27;s headshot.&quot; decoding=&quot;async&quot; height=&quot;350&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 350px) 350px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/j1ZYEFXC0JsAlpQsswJX.png?auto=format&amp;w=700 700w&quot; width=&quot;350&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Melanie Sumner&lt;/strong&gt;: My name is Melanie Sumner and I am a software engineer
specializing in digital accessibility. I&#39;ve been writing code for the web for
25 years. My first career was… kind of a spy. I was an intelligence analyst in
the US Navy, and coding was my hobby.&lt;/p&gt;
&lt;p&gt;I didn&#39;t really like being a spy. I wasn&#39;t fond of death, it turns out. As most
people are not, when they have to be closer to it. I had to decide what I
wanted to do next, and it was time to turn my hobby into my career. In the last
10 years, I&#39;ve really focused on software engineering in the accessibility
space, specifically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You don&#39;t often hear, &amp;quot;Oh first I was a spy.&amp;quot; No big deal. What
brought you into accessibility work?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;:  I was working at the University of North Carolina [UNC] Chapel
Hill at the time, in the Department of Development. They don&#39;t mean development
like web development, they mean development like fundraising.&lt;/p&gt;
&lt;p&gt;My direct manager had a vision impairment, and he had to zoom everything to
400% to see it. He was a fantastic software engineer. Probably the best manager
I&#39;ve ever had, actually. But he was always breaking my stuff, because he would
zoom in to look at my work. If I hadn&#39;t thought about building things
responsively, they would break.&lt;/p&gt;
&lt;p&gt;My manager&#39;s boss was blue colorblind. I don&#39;t know if you know what UNC blue
looks like, but it&#39;s this &lt;a href=&quot;https://identity.unc.edu/brand/color-palette/&quot; rel=&quot;noopener&quot;&gt;light sky blue color&lt;/a&gt;.
And they &lt;em&gt;loved&lt;/em&gt; using it on white.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: (laughs) Oh no.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: His boss was always complaining that he could never see my work! I
had to develop a set of complementary colors and a color scheme for our sites.
That got me thinking about color contrast and thinking about how people who are
colorblind (or otherwise visually impaired) use the web.&lt;/p&gt;
&lt;p&gt;Because UNC is a state university, there&#39;s a
&lt;a href=&quot;https://www.section508.gov/develop/applicability-conformance/&quot; rel=&quot;noopener&quot;&gt;US federal requirement&lt;/a&gt;
to conform with WCAG accessibility level AA. We aimed for level AAA because
it&#39;s an education institution.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Take the Learn Accessibility module &lt;a href=&quot;https://web.dev/learn/accessibility/measure/&quot;&gt;How is digital accessibility measured?&lt;/a&gt; to read more about WCAG conformance levels. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;As I learned more about the state and federal requirements and began reading
the &lt;a href=&quot;https://www.w3.org/TR/WCAG21/&quot; rel=&quot;noopener&quot;&gt;W3C Accessibility spec&lt;/a&gt;, I thought, &amp;quot;All of
this makes sense.&amp;quot; Most of the web wasn&#39;t compliant, from what I could see. Of
course, people have been working on web accessibility for as long as the web
has existed. Sometimes JavaScript engineers (in particular) are a little slow
on the uptake when it comes to digital accessibility.&lt;/p&gt;
&lt;p&gt;I call accessibility the final frontier of the web. Lots of good people work on
automation for accessibility—and we need to work on solutions the same
way that we&#39;ve approached other hard problems, such as performance and security.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: You&#39;ve probably read a lot of long complex documents, in the
Navy and at UNC. Did you find it was challenging to understand the spec?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I had to read it about five times before I understood it—and
I&#39;d read other specs before. I always tell people, don&#39;t feel bad if you don&#39;t
understand it, because I had to read the spec five times! I&#39;m not even joking.&lt;/p&gt;
&lt;p&gt;It takes a lot of time to get used to spec language. And if you don&#39;t interpret
it correctly, you might do the wrong thing. Also it&#39;s important to understand
that a lot of the spec language is meant for browser developers. Look for
&amp;quot;authors should,&amp;quot; because that&#39;s a reference to web developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: A lot on the web could be better if more developers knew how to
decipher the specs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: There&#39;s a lot to be said for sites that do that interpretation for
you. I built &lt;a href=&quot;https://a11y-automation.dev/&quot; rel=&quot;noopener&quot;&gt;a11y-automation.dev&lt;/a&gt; and that site
is kind of like my baby, my side project. I try to itemize every accessibility
violation and link it to the WCAG success criteria in question. If there&#39;s
automation to prevent the error, I&#39;ll offer that solution.&lt;/p&gt;
&lt;p&gt;You could familiarize yourself with the list of potential violations, but more
important is learning how to fix it. For automated fixes that don&#39;t exist,
maybe you&#39;re inspired to write a linter or a template—maybe you get
inspired to write some kind of test.&lt;/p&gt;
&lt;p&gt;I prefer to work in open source, because you get to kind of riff off each
other, offer an improvement (sometimes an improvement, sometimes not, but we
all try our best). We build on each other&#39;s stuff, and then we end up with this
really great outcome for the web.&lt;/p&gt;
&lt;h2 id=&quot;how-to-fund-accessibility&quot;&gt;How to fund accessibility &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-melanie/#how-to-fund-accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-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; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&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;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Learn about the &lt;a href=&quot;https://web.dev/learn/accessibility/why/#business-impact&quot;&gt;business impact&lt;/a&gt; of building accessible websites. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I was really drawn to
&lt;a href=&quot;http://pleasefunda11y.com/&quot; rel=&quot;noopener&quot;&gt;pleasefunda11y.com&lt;/a&gt;. It&#39;s really important to get
developers to learn how to build accessible sites, but they won&#39;t always have
the resources without having executive leadership funding and approval. Why did
you decide to build this site?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;:  I was frustrated because accessibility is so underfunded. All of
the open source funding  seems to keep going to CSS. And I love CSS, we can do
so much with it.&lt;/p&gt;
&lt;p&gt;I built the site because &lt;a href=&quot;https://twitter.com/addyosmani&quot; rel=&quot;noopener&quot;&gt;Addy Osmani&lt;/a&gt;—a
Chrome software engineering manager—reached out and said he saw I was
asking for accessibility funding, but he wanted advice on what specific work
could be funded. That&#39;s a big problem: open source funders want to give money
to specific projects, not general ideas that have no determined outcome. I took
some time to write down some specific initiatives, what&#39;s needed and how
they&#39;ll help make sites accessible.&lt;/p&gt;
&lt;p&gt;Even if companies build towards these efforts without me, we could move
accessibility on the web forward in a really significant way. It&#39;s a very small
spend by comparison to other web efforts, and it would have a huge impact on
people&#39;s lives.&lt;/p&gt;
&lt;p&gt;The current way of thinking is often, &amp;quot;Well, how many people have a
disability?&amp;quot; It should be: &amp;quot;What is any person&#39;s relationship to their
technology?&amp;quot;&lt;/p&gt;
&lt;p&gt;And some folks have told me, &amp;quot;Well, I don&#39;t think color blindness is a
disability.&amp;quot; You may not identify yourself as having a disability if you&#39;re
colorblind, but it does affect your relationship with technology.&lt;/p&gt;
&lt;figure&gt;
&lt;ul class=&quot;stats bg-state-info-bg color-state-info-text&quot;&gt;
  &lt;div class=&quot;stats__item&quot;&gt;
    &lt;p class=&quot;stats__figure&quot;&gt;
      15
      &lt;sub&gt;%&lt;/sub&gt;
    &lt;/p&gt;
    &lt;p&gt;people self-identify as disabled.&lt;/p&gt;
    &lt;p&gt;&lt;sub&gt;&lt;a href=&quot;https://www.who.int/teams/noncommunicable-diseases/sensory-functions-disability-and-rehabilitation/world-report-on-disability&quot; aria-label=&quot;View the statistic source, WHO.&quot;&gt;Source&lt;/a&gt;&lt;/sub&gt;&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class=&quot;stats__item&quot;&gt;
    &lt;p class=&quot;stats__figure&quot; style=&quot;white-space: nowrap&quot;&gt;
      253 
      &lt;sub&gt;m&lt;/sub&gt;
    &lt;/p&gt;
    &lt;p&gt;people with visual impairments.&lt;/p&gt;
    &lt;p&gt;&lt;sub&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5820628/&quot; aria-label=&quot;View the statistic source, National Library of Medicine.&quot;&gt;Source&lt;/a&gt;&lt;/sub&gt;&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class=&quot;stats__item&quot;&gt;
    &lt;p class=&quot;stats__figure&quot;&gt;
      39
    &lt;/p&gt;
    &lt;p&gt;countries with web accessibility law.&lt;/p&gt;
    &lt;p&gt;&lt;sub&gt;&lt;a href=&quot;https://www.w3.org/WAI/policies/&quot; aria-label=&quot;View the statistic source, Web Accessibility Intiative.&quot;&gt;Source&lt;/a&gt;&lt;/sub&gt;&lt;/p&gt;
  &lt;/div&gt;
&lt;/ul&gt;
&lt;figcaption&gt;
  Learn more about the statistics in Learn Accessibility&#39;s first module:
  &lt;a href=&quot;https://web.dev/learn/accessibility/why/&quot;&gt;What is digital accessibility, and why does it matter?&lt;/a&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Tell me more about understanding your relationship with
technology. How does that relate to accessibility?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: For example, if you are neurodiverse, maybe you need really simple
language and very clear directions. You may be better served navigating through
three or four screens in a flow, making a few choices at a time until you get
to the end. There&#39;s not good guidance for modern technical applications.&lt;/p&gt;
&lt;p&gt;We have whole companies that do devops, and if you try to use some of those
websites, you&#39;re like, &amp;quot;Oh my god,&amp;quot; you know? We try to pack the kitchen sink
into all of our interfaces these days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Can you share an example?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: For example, GitHub has dropdowns with nested tabs. And
[exasperated sigh]. I can&#39;t get upset (even if I&#39;m frustrated). The modern web
has to grow to meet new demands. But we also have a responsibility to build in
a way that doesn&#39;t leave people behind.&lt;/p&gt;
&lt;p&gt;That&#39;s what drives me, that&#39;s my passion. I don&#39;t want somebody to not be able
to get a job because the tools they&#39;d have to use at the job are not accessible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: One hundred percent. And people often think about building
accessible products for their external users, but not necessarily thinking
about their employees.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I thought, you know what, this funding advice would probably
benefit everyone.&lt;/p&gt;
&lt;p&gt;I hear from engineers all the time that they&#39;d love to do accessibility but &amp;quot;my
company doesn&#39;t care.&amp;quot; I bet they do care! You just need to bridge the business
logic gap. Show them the beneficial outcome for the business. The &lt;a href=&quot;https://github.com/MelSumner/please-fund-a11y&quot; rel=&quot;noopener&quot;&gt;site is open
source&lt;/a&gt;, of course, and I love
contributions and edits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Accessibility is often left to the end of the process, like, &amp;quot;Oh
we can just make this accessible later.&amp;quot; But it&#39;s going to take a lot more time
to add it later than it would to integrate accessible practices throughout the
project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I often say, &amp;quot;Do you want to pay to build it once or do you want
to pay to build it twice?&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;emberjs-and-the-core-accessibility-team&quot;&gt;Ember.js and the core accessibility team &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-melanie/#emberjs-and-the-core-accessibility-team&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I know you&#39;re also involved in the Ember.js framework core team.
How did you get involved?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I was hired to work at JPMorgan Chase, on their corporate
investment banking platforms. Ember is a heavy duty JavaScript framework used
when you need a really stable (maybe even kind of boring) base, that can help
you avoid writing code that loses a lot of bank dollars. Ember has a backwards
compatibility guarantee—you can upgrade every time, even if you hit a
major version. We really try to do things incrementally, so it doesn&#39;t break
your app.&lt;/p&gt;
&lt;p&gt;Anyway, I showed up to an Ember conference, and I met a bunch of people in the
community. Ember folks were so kind. And there&#39;s
&lt;a href=&quot;https://emberjs.com/guidelines/&quot; rel=&quot;noopener&quot;&gt;a really strong code of conduct&lt;/a&gt; that I just
hadn&#39;t seen yet in other places.&lt;/p&gt;
&lt;p&gt;When I got out of the military, I wanted to go into security. I went to an
infosec meetup, and didn&#39;t see any other woman there. One of the older guys
looked at me and said, &amp;quot;Are you sure you&#39;re in the right room, sweetheart?&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: [Groans] It hurts. And it&#39;s completely unsurprising. I&#39;ve
experienced something similar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I want to say this was 2011, maybe 2012? The landscape has changed
a lot. I stayed that night, through that meetup, to prove a point. I wasn&#39;t
gonna let that comment shut me down. I cracked jokes, took good notes, and
participated in the conversation, so people knew I was there. I feel like a lot
of my career has been proving men wrong.&lt;/p&gt;
&lt;p&gt;But, I don&#39;t want women to become software engineers just to prove men wrong. I
wanted to be a software engineer to build amazing things, because it&#39;s fun to
do. Women should have that career option.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Absolutely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I shared what I knew about accessibility with the Ember community,
because obviously as a banking platform, you have to conform to the US federal
requirements. Yehuda Katz and Tom Dale said, &amp;quot;We have a gap on the team. We
have a lot of JavaScript experts, performance experts, people out-of-this-world
smart, and we need someone with accessibility knowledge.&amp;quot; And they invited me
to join the core team.&lt;/p&gt;
&lt;p&gt;I&#39;m working on initiatives to help make Ember accessible by default. That means
when you say &lt;code&gt;ember new &amp;lt;my-app-name&amp;gt;&lt;/code&gt;, you should immediately pass WCAG
success criteria.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: I saw a long list of accessibility tools for Ember on GitHub.
Have you found that people in the Ember community are excited to contribute to
those tools?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: That&#39;s been a really exciting part of this work. I wrote
accessibility linting rules for Ember while working at LinkedIn. Then I left
LinkedIn to work for Hashicorp, and other folks are still contributing to the
linter because it&#39;s useful for them. That&#39;s the part of this work that gives me
chills and gets me excited.&lt;/p&gt;
&lt;p&gt;We accept that, as a baseline, accessibility is a civil right. That&#39;s not up
for discussion.&lt;/p&gt;
&lt;p&gt;What we discuss is: What can we implement? When? How do we make it? How do we
teach this and make it backwards compatible? How do we help developers provide
accessibility support without a huge extra feature that they have to build or
plan for?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: Accessibility is a civil right. That gives me chills! It
should just be a thing we all know as truth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: I&#39;ve had people say uninformed things to me, like &amp;quot;I wouldn&#39;t use
the internet if I was blind.&amp;quot; Or, &amp;quot;Why do I have to think about disabilities
when it&#39;s only 5% of my users, when it&#39;s working for 90% of my users?&amp;quot; I won&#39;t
have those discussions, because they&#39;re often used to distract from the work.&lt;/p&gt;
&lt;p&gt;When you write accessible code, you&#39;re going to get performance boosts because
you&#39;re thinking about building sites informed by W3C specs. You&#39;ll use the
semantic HTML instead of just divs, and you&#39;ll use headings. You&#39;ll choose a
&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; instead of adding a click event to a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, and you&#39;ll get
performance enhancements.&lt;/p&gt;
&lt;h2 id=&quot;do-one-thing-automate-accessibility&quot;&gt;Do one thing: automate accessibility &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/community-highlight-melanie/#do-one-thing-automate-accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alexandra&lt;/strong&gt;: What&#39;s one thing web developers should do to build accessible
websites?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Melanie&lt;/strong&gt;: Add automation. Start with an existing linter for whatever
framework you have, whatever kind of code you&#39;re using. I don&#39;t care which one
you use! Your build should break if one of those rules is broken.&lt;/p&gt;
&lt;p&gt;Some things can&#39;t be automated, because AI can&#39;t yet decipher intent. For
example, an image&#39;s alt text value should be &lt;em&gt;meaningful&lt;/em&gt;, but what does that
actually mean? Right now, a human needs to discern that, and not automation.&lt;/p&gt;
&lt;p&gt;But an automated tool can tell you, &amp;quot;You&#39;re not passing
&lt;a href=&quot;https://web.dev/learn/accessibility/color-contrast/&quot;&gt;color contrast&lt;/a&gt;.&amp;quot; Just
fix it. Don&#39;t fight it, don&#39;t say, &amp;quot;But I don&#39;t want to, I prefer it this way.&amp;quot;
This is not about you. It&#39;s about making what we do available for everyone in
the world every day.&lt;/p&gt;
&lt;p&gt;Accessibility is a journey, and you&#39;re always going to be learning. I&#39;ve been
specializing in accessibility for over a decade, and I&#39;m still learning new
things all the time!  Don&#39;t be defensive, just do it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Keep up with Melanie&#39;s work on her website at
&lt;a href=&quot;https://melanie.codes/&quot; rel=&quot;noopener&quot;&gt;melanie.codes&lt;/a&gt; and Twitter
&lt;a href=&quot;https://twitter.com/a11yMel&quot; rel=&quot;noopener&quot;&gt;@a11yMel&lt;/a&gt;. Check out her accessibility resources
on &lt;a href=&quot;https://pleasefunda11y.com/&quot; rel=&quot;noopener&quot;&gt;pleasefunda11y.com&lt;/a&gt;,
&lt;a href=&quot;https://a11y-info.com/&quot; rel=&quot;noopener&quot;&gt;a11y-info.com&lt;/a&gt;, and
&lt;a href=&quot;https://a11y-automation.dev/&quot; rel=&quot;noopener&quot;&gt;a11y-automation.dev&lt;/a&gt;.&lt;/p&gt;
</content>
      <author>
          <name>Alexandra White</name>
        </author>
    </entry>
    
    
    
    <entry>
      <title>Building a floating action button (FAB) component</title>
      <link href="https://web.dev/building-a-fab-component/"/>
      <updated>2022-10-06T00:00:00Z</updated>
      <id>https://web.dev/building-a-fab-component/</id>
      <content type="text/html" mode="escaped">&lt;p&gt;In this post I want to share my thoughts on how to build color-adaptive,
responsive, and accessible FAB components. &lt;a href=&quot;https://gui-challenges.web.app/FAB/dist/&quot; rel=&quot;noopener&quot;&gt;Try the
demo&lt;/a&gt; and &lt;a href=&quot;https://github.com/argyleink/gui-challenges&quot; rel=&quot;noopener&quot;&gt;view the
source&lt;/a&gt;!&lt;/p&gt;
&lt;style&gt;
  .auto-aspect {
    aspect-ratio: auto;
  }
&lt;/style&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/g3TG5gGs3qmGxBfaUIXf.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;If you prefer video, here&#39;s a YouTube version of this post:&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;RXopH5t2Kww&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FABs are more common on mobile than desktop, but they&#39;re prevalent in both
scenarios. They keep primary actions in view, making them convenient and
omnipresent. This user experience style was made famous by Material UI and their
suggestions for usage and placement can be &lt;a href=&quot;https://material.io/components/buttons-floating-action-button&quot; rel=&quot;noopener&quot;&gt;found
here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;elements-and-styles&quot;&gt;Elements and styles &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#elements-and-styles&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The HTML for these controls involves a container element and a set of one or
more buttons. The container positions the FABs within the viewport and manages a
gap between the buttons. The buttons can be mini or default, giving some nice
variety between primary and secondary actions.&lt;/p&gt;
&lt;h3 id=&quot;fab-container&quot;&gt;FAB container &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fab-container&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This element can be a regular &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; but let&#39;s do our unsighted users a favor
and tag it with some helpful attributes to explain the purpose and contents of
this container.&lt;/p&gt;
&lt;h4 id=&quot;fabs-markup&quot;&gt;FABs markup &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fabs-markup&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Start with a &lt;code&gt;.fabs&lt;/code&gt; class for CSS to hook into for style, then add
&lt;code&gt;role=&amp;quot;group&amp;quot;&lt;/code&gt; and &lt;code&gt;aria-label&lt;/code&gt; so it&#39;s  not just a generic container, it&#39;s
named and purposeful.&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;fabs&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;group&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Floating action buttons&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- buttons will go here --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;h4 id=&quot;fabs-style&quot;&gt;FABs style &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fabs-style&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In order for FABs to be convenient they stick within the viewport at all times.
This is a great use case for position
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/position&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;fixed&lt;/code&gt;&lt;/a&gt;. Within this
viewport position I chose to use
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/inset-block&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;inset-block&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/inset-inline&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;inset-inline&lt;/code&gt;&lt;/a&gt; so the
position will compliment the user&#39;s document mode, like right-to-left or
left-to-right. Custom properties are also used to prevent repetition and ensure
equal distance from the bottom and side edges of the viewport:&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;.fabs&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_viewport-margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2.5vmin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&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 property&quot;&gt;inset-block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_viewport-margin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;inset-inline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_viewport-margin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;Next I give the container display
&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; and change its
layout direction to
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/flex-direction&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;column-reverse&lt;/code&gt;&lt;/a&gt;.
This stacks the children on top of each other (column) and also reverses their
visual order. This has the effect of making the first focusable element the
bottom element instead of the top, which would be where focus goes normally per
the HTML document. Reversing the visual order unites the experience for sighted
users and keyboard users, as the styling of the primary action as larger than
the mini buttons indicates to sighted users that it&#39;s a primary action, and
keyboard users will focus it as the first item in the source.&lt;/p&gt;
&lt;img alt=&quot;Two fab buttons are shown with DevTools overlaying their grid layout. Shows the gap between them with a striped pattern and also shows their computed height and width.&quot; decoding=&quot;async&quot; height=&quot;501&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/PkRWiv4mtfCDXujti7lL.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;.fabs&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  …&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-direction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; column-reverse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;place-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_viewport-margin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;Centering is handled 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&lt;/code&gt;&lt;/a&gt;, and
&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; adds space between any
FAB buttons placed in the container.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/2AKk0IQVDdvMDGnBVk6J.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;fab-buttons&quot;&gt;FAB buttons &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fab-buttons&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Time to style some buttons to look like they&#39;re floating over top of everything.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/XFklV07Wsn7q82rEBYD6.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h4 id=&quot;default-fab&quot;&gt;Default FAB &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#default-fab&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first button to style is the default button. This will serve as the base for
all the FAB buttons. Later we&#39;ll create a variant that achieves an alternative
appearance while modifying as little of these base styles as possible.&lt;/p&gt;
&lt;h4 id=&quot;fab-markup&quot;&gt;FAB markup &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fab-markup&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element is the right choice. We&#39;ll start with this as the base
because it comes with great mouse, touch, and keyboard user experience. The most
crucial aspect of this markup is to hide the icon from screenreader users with
&lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; and add the necessary label text to the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; markup
itself. When adding labels in these cases I also like adding a &lt;code&gt;title&lt;/code&gt; so mouse
users can get information about what the icon is hoping to communicate.&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-icon&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;plus&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fab&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Add new action&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Add new action&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;...&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;fab-style&quot;&gt;FAB style &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#fab-style&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;First let&#39;s turn the button into a padded round button with a strong shadow, as
these are the first defining features of the button:&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;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;calc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_size&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 property&quot;&gt;border-radius&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;--radius-round&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;box-shadow&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;--shadow-4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next let&#39;s add color. We&#39;ll use a strategy we&#39;ve used in GUI Challenges before.
Create a clearly named set of custom properties that statically hold the light
and dark colors, then an adaptive custom property that will be set to either the
light or the dark variables depending on the user&#39;s system preference for
colors:&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  …&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* light button and button hover */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_light-bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--pink-6&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_light-bg-hover&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;--pink-7&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* dark button and button hover */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_dark-bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--pink-4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_dark-bg-hover&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;--pink-3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* adaptive variables set to light by default */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_light-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* static icon colors set to the adaptive foreground variable */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_light-fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_dark-fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_light-fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* use the adaptive properties on some styles */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;:is(:active, :hover, :focus-visible)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_light-bg-hover&lt;span 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;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_dark-bg-hover&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* if users prefers dark, set adaptive props to dark */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_dark-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_fg&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;--_dark-fg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next add some styles to help the SVG icons fit the space.&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;…&lt;br /&gt;&lt;br /&gt;  &amp;amp; &gt; svg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;inline-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;block-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px&lt;span class=&quot;token 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;Last, remove the tap highlight from the button since we&#39;ve added our own visual
feedback for interaction:&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;-webkit-tap-highlight-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/qjMTHfEqKa6o2zRRcvKg.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h4 id=&quot;mini-fab&quot;&gt;Mini FAB &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#mini-fab&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The goal of this section is to create a variant for the FAB button. By making
some of the FABs smaller than the default action, we can promote the action the
user performs the most often.&lt;/p&gt;
&lt;h5 id=&quot;mini-fab-markup&quot;&gt;Mini FAB markup &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#mini-fab-markup&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;The HTML is the same as a FAB but we add a &amp;quot;.mini&amp;quot; class to give CSS a hook into
the variant.&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-icon&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;heart&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fab mini&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Like action&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Like action&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;...&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h5 id=&quot;mini-fab-style&quot;&gt;Mini FAB style &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#mini-fab-style&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Thanks to usage of custom properties, the only change needed is an adjustment to
the &lt;code&gt;--_size&lt;/code&gt; variable.&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;.fab.mini&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img alt=&quot;A screenshot of the two fab buttons stacked and the top button is smaller than the one on the bottom.&quot; decoding=&quot;async&quot; height=&quot;410&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 664px) 664px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vS06HQ1YTsbMKSFTIPl2iogUQP73/bYhvGgYmV0OiztY7j58r.png?auto=format&amp;w=1328 1328w&quot; width=&quot;664&quot; /&gt;
&lt;h2 id=&quot;accessibility&quot;&gt;Accessibility &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#accessibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most important part to remember for accessibility with FABs is placement
within the keyboard flow of the page. This demo only has the FABs, there&#39;s
nothing to compete with in terms of keyboard order and flow, which means it
doesn&#39;t have an opportunity to demonstrate a meaningful keyboard flow. In a
scenario where there&#39;s competing elements for focus, I suggest thinking deeply
about where in that flow should a user find themselves entering into the FAB
button flow.&lt;/p&gt;
&lt;figure data-size=&quot;full&quot;&gt;
  &lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/Sgr0PllZvJ9eDTP3LSf6.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    Keyboard interaction demonstration
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once the user has focused into the FAB container, we&#39;ve already added
&lt;code&gt;role=&amp;quot;group&amp;quot;&lt;/code&gt; and &lt;code&gt;aria-label=&amp;quot;floating action buttons&amp;quot;&lt;/code&gt; which inform screen
reader users about the contents of what they have focused. Strategically I&#39;ve
placed the default FAB first, so that users find the primary action first. I
then use &lt;code&gt;flex-direction: column-reverse;&lt;/code&gt; to visually order the primary button
on the bottom, close to the users fingers for easy access. This is a nice win
because the default button is visually prominent and also first for keyboard
users, giving them very similar experiences.&lt;/p&gt;
&lt;p&gt;Lastly, don&#39;t forget to hide your icons from screen reader users and ensure you
provide them with a label for the button so it&#39;s not a mystery. This has been
done in the HTML already with &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; on the &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; and
&lt;code&gt;aria-label=&amp;quot;Some action&amp;quot;&lt;/code&gt; on the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;s.&lt;/p&gt;
&lt;h2 id=&quot;animation&quot;&gt;Animation &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#animation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Various types of animation can be added to enhance the user experience. Like in
other GUI Challenges, we&#39;ll set up a couple of custom properties to hold the
intent of a reduced motion experience and a full motion experience. By default
the styles will assume the user wants reduced motion, then using the
&lt;code&gt;prefers-reduced-motion&lt;/code&gt; media query swap the transition value to full motion.&lt;/p&gt;
&lt;h3 id=&quot;a-reduced-motion-strategy-with-custom-properties&quot;&gt;A reduced motion strategy with custom properties &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#a-reduced-motion-strategy-with-custom-properties&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Three custom properties are created in the following CSS: &lt;code&gt;--_motion-reduced&lt;/code&gt;,
&lt;code&gt;--_motion-ok&lt;/code&gt;, and &lt;code&gt;--_transition&lt;/code&gt;. The first two hold appropriate transitions
given the user&#39;s preference, and the last variable &lt;code&gt;--_transition&lt;/code&gt; will be set
to either &lt;code&gt;--_motion-reduced&lt;/code&gt; or &lt;code&gt;--_motion-ok&lt;/code&gt; respectively.&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;.fab&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;/* box-shadow and background-color can safely be transitioned for reduced motion users */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_motion-reduced&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    box-shadow .2s &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ease-3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    background-color .3s &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ease-3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* add transform and outline-offset for users ok with motion */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_motion-ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_motion-reduced&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    transform .2s &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ease-3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    outline-offset 145ms &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ease-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;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* default the transition styles to reduced motion */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--_transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_motion-reduced&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* set the transition to our adaptive transition custom property*/&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_transition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* if motion is ok, update the adaptive prop to the respective transition prop */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;--_transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--_motion-ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;With the above in place, changes to &lt;code&gt;box-shadow&lt;/code&gt;, &lt;code&gt;background-color&lt;/code&gt;,
&lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;outline-offset&lt;/code&gt; can be transitioned, giving the user nice UI
feedback that their interaction has been received.&lt;/p&gt;
&lt;p&gt;Next, add a little bit more flair to the &lt;code&gt;:active&lt;/code&gt; state by adjusting
&lt;code&gt;translateY&lt;/code&gt;a little bit, this gives the button a nice pressed effect:&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;…&lt;br /&gt;&lt;br /&gt;  &amp;amp;:active&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/lc16x8xZb8SAjvn3j4nK.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Then lastly, transition any changes to the SVG icons in the buttons:&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;.fab&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;…&lt;br /&gt;&lt;br /&gt;  &amp;amp;[data-icon=&quot;plus&quot;]:hover &gt; svg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotateZ&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.25turn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; &gt; svg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; no-preference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;will-change&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform .5s &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--ease-squish-3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span 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;&lt;video autoplay=&quot;&quot; class=&quot;auto-aspect&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/vS06HQ1YTsbMKSFTIPl2iogUQP73/fAZut0C45mYdXvcX1kz4.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&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 easing function &lt;code&gt;--ease-squish-3&lt;/code&gt; is part of Open Props and is responsible for the elastic bouncy effect on the rotation. Find more props like it at the &lt;a href=&quot;https://open-props.style/&quot;&gt;Open Props document website&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you know how I did it, how would you‽ 🙂&lt;/p&gt;
&lt;p&gt;Let&#39;s diversify our approaches and learn all the ways to build on the web.&lt;/p&gt;
&lt;p&gt;Create a demo, &lt;a href=&quot;https://twitter.com/argyleink&quot; rel=&quot;noopener&quot;&gt;tweet me&lt;/a&gt; links, and I&#39;ll add it
to the community remixes section below!&lt;/p&gt;
&lt;h2 id=&quot;community-remixes&quot;&gt;Community remixes &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#community-remixes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Nothing to see here yet.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;w-headline-link&quot; href=&quot;https://web.dev/building-a-fab-component/#resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/argyleink/gui-challenges/tree/main/FAB&quot; rel=&quot;noopener&quot;&gt;Source code&lt;/a&gt; on Github&lt;/li&gt;
&lt;/ul&gt;
</content>
      <author>
          <name>Adam Argyle</name>
        </author>
    </entry>
    
</feed>
