<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Addy Osmani on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Addy Osmani</name>
  </author>
  <link href="https://web.dev/authors/addyosmani/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LJyNTOzyWbowv2mrlzPS.jpeg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Eng Manager working on Chrome and Web Platform</subtitle>
  
  
  <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="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;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;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/fetch-priority/&quot;&gt;&lt;code&gt;fetchpriority&lt;/code&gt; attribute&lt;/a&gt;, 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;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;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;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>What&#39;s new in PageSpeed Insights</title>
    <link href="https://web.dev/whats-new-pagespeed-insights/"/>
    <updated>2021-11-03T00:00:00Z</updated>
    <id>https://web.dev/whats-new-pagespeed-insights/</id>
    <content type="html" mode="escaped">&lt;p&gt;Over the years, &lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed
Insights&lt;/a&gt; (PSI) has
evolved into a one-stop source for both
&lt;a href=&quot;https://web.dev/speed-tools/#field-data&quot;&gt;field&lt;/a&gt;
and
&lt;a href=&quot;https://web.dev/speed-tools/#lab-data&quot;&gt;lab data&lt;/a&gt;.
It integrates information from the
&lt;a href=&quot;hhttps://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome UX Report&lt;/a&gt;
(CrUX) and &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;
diagnostics to provide insights that help improve the performance of your
website.&lt;/p&gt;
&lt;p&gt;Today, we are excited to announce an updated version of PSI! While it is a
critical element in our &lt;a href=&quot;https://web.dev/vitals-tools/&quot;&gt;speed tooling suite&lt;/a&gt;,
the PSI code base was ten years old, contained a lot of legacy code, and was due
for a redesign. We used this as an opportunity to address interface-related
issues in PSI which have sometimes made it difficult for users to navigate the
report. Our primary goals were to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make the UI more intuitive by clearly differentiating between data
derived from a synthetic environment and data collected from users in the
field.&lt;/li&gt;
&lt;li&gt;Clearly communicate how the &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt; assessment is calculated in the UI.&lt;/li&gt;
&lt;li&gt;Modernize the look and feel of PSI, leveraging &lt;a href=&quot;https://material.io/design&quot; rel=&quot;noopener&quot;&gt;Material Design&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post introduces the new features in PSI which will be released later this
year.&lt;/p&gt;
&lt;h2 id=&quot;whats-new&quot;&gt;What&#39;s new? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#whats-new&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The PSI UI redesign aims to improve the presentation of the report data and add
clarity and granularity to the data available in the report. The new UI is aimed
to be more intuitive and helps developers quickly discover lab and field
performance insights for their pages. The fundamental changes to the UI
include:&lt;/p&gt;
&lt;h3 id=&quot;clear-separation-of-field-and-lab-data&quot;&gt;Clear separation of field and lab data &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#clear-separation-of-field-and-lab-data&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have changed the UI to distinctly separate field data from lab data. Labels
for &amp;quot;Field Data&amp;quot; and &amp;quot;Lab data&amp;quot; have been replaced with text that indicates what
the data means and how it can help. We have also brought the Field data section
to the top. The traditional lab-based performance score, which is currently
shown at the top, has been moved down to the Lab data section to avoid ambiguity
about the origin of the score.&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 don&#39;t know the difference between lab and field data, check out the &lt;a href=&quot;https://web.dev/how-to-measure-speed/&quot;&gt;explainer on web.dev&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;figure&gt;
&lt;img alt=&quot;discover what your real users are experiencing&quot; decoding=&quot;async&quot; height=&quot;436&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jM0GYMrQZcPymVXdLOLP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Section for field data
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img alt=&quot;Diagnose performance issues&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/wQ9RGcJAcBBc4SUDK7Dz.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Section for lab data
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;core-web-vitals-assessment&quot;&gt;Core Web Vitals assessment &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#core-web-vitals-assessment&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Core Web Vitals assessment result, which earlier appeared as a single word
&amp;quot;passed&amp;quot; or &amp;quot;failed&amp;quot; in Field Data, now stands out as a separate subsection with
a distinct icon.&lt;/p&gt;
&lt;p&gt;Note that there is no change in the assessment process for Core Web Vitals. The
Core Web Vitals metrics FID, LCP, and CLS, may be aggregated at either the page
or origin level. For aggregations with sufficient data in all three metrics, the
aggregation passes the Core Web Vitals assessment if the 75th percentiles of all
three metrics are Good. Otherwise, the aggregation does not pass the assessment.
If the aggregation has insufficient FID data, it will pass the assessment if
both the 75th percentiles of LCP and CLS are Good. If either LCP or CLS has
insufficient data, the page or origin-level aggregation cannot be assessed.&lt;/p&gt;
&lt;h3 id=&quot;labels-for-mobile-and-desktop-performance&quot;&gt;Labels for mobile and desktop performance &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#labels-for-mobile-and-desktop-performance&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We changed the navigation menu at the top and included links for mobile and
desktop centrally on the report page. The links are now easily visible and
distinctly indicate the platform for which the data is being shown. Doing this
also helped make the navigation bar cleaner.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Older (at the time of writing) version of PageSpeed Insights&quot; decoding=&quot;async&quot; height=&quot;97&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/hEv5XuTeVV98Z3AS59bQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    PSI mobile and desktop labels before
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Newer version of the navigation bar&quot; decoding=&quot;async&quot; height=&quot;149&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vi5j7ouZtmWwqN9BRsUD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
        PSI mobile and desktop labels after
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;origin-summary&quot;&gt;Origin Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#origin-summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Origin Summary, which provides the aggregated CrUX score for all pages from
the origin, currently appears on click of a checkbox. We have moved this report
section to a new tab, &amp;quot;Origin&amp;quot;, under the Field Data section.&lt;/p&gt;
&lt;img alt=&quot;Origin summary for the new PageSpeed Insights refresh.&quot; decoding=&quot;async&quot; height=&quot;381&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/5Kn5meWq0sWwCLT69lMb.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;additional-helpful-information&quot;&gt;Additional helpful information &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#additional-helpful-information&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The report now includes a new information section at the bottom of each field
and lab card sharing the following details about the sampled data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data collection period&lt;/li&gt;
&lt;li&gt;Visit durations&lt;/li&gt;
&lt;li&gt;Devices&lt;/li&gt;
&lt;li&gt;Network connections&lt;/li&gt;
&lt;li&gt;Sample size&lt;/li&gt;
&lt;li&gt;Chrome versions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This information should enhance the distinction between lab and field data and
help users who have previously been uncertain how the two data sources (lab and
field) might differ.&lt;/p&gt;
&lt;img alt=&quot;Enhanced section of information sharing data about field and lab sampling and configuration data&quot; decoding=&quot;async&quot; height=&quot;368&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/jVxqisC0x6I5viUGgjAD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;expand-view&quot;&gt;Expand view &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#expand-view&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have a new &amp;quot;Expand view&amp;quot; feature that adds a drill-down function to the field
data section and allows you to view granular details for the Core Web Vitals
metrics.&lt;/p&gt;
&lt;img alt=&quot;Newly expanded view with a drill-down for field data metrics.&quot; decoding=&quot;async&quot; height=&quot;515&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/UFVgoK1gJBYk5DLhFwIn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;page-image&quot;&gt;Page image &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#page-image&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have removed the image of the loaded page, which appears right next to the
field data. The image and thumbnails of the page displaying the loading sequence
will both be available in the lab data section.&lt;/p&gt;
&lt;img alt=&quot;Loaded page image next to the lab data.&quot; decoding=&quot;async&quot; height=&quot;444&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/dnIsJA35tj7vs6qgybRM.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;For up to date product documentation, visit
&lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/about&quot; rel=&quot;noopener&quot;&gt;https://developers.google.com/speed/docs/insights/.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;updates-to-webdevmeasure&quot;&gt;Updates to web.dev/measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#updates-to-webdevmeasure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To reduce inconsistency between the different tools in our performance toolbox,
we are also updating &lt;a href=&quot;https://web.dev/measure/&quot;&gt;web.dev/measure&lt;/a&gt; to be directly powered by the &lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/get-started&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously, developers would run reports via both the PSI tool and /measure
and see different Lighthouse numbers. One of the main reasons for differences
was because /measure originated all tests from the U.S. (due to it previously
having a cloud backend that was US-based).&lt;/p&gt;
&lt;p&gt;With /measure calling the same API directly as the PSI UI, developers will get
a more consistent experience when using PSI and /measure. We have also made
a few tweaks to /measure based on how users use the tool. This means that the
signed-in experience for /measure will be going away, but the most used
functionality—seeing multiple categories—will still be available for use.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The old version of the measure page.&quot; decoding=&quot;async&quot; height=&quot;377&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/KFZmLMU2iSxkPDph7FTV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    web.dev/measure before
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The refreshed version of the measure tool focusing on offering page quality measurement.&quot; decoding=&quot;async&quot; height=&quot;696&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/C04zQEkxtSQqPEQedNN7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    web.dev/measure after
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;psi-today&quot;&gt;PSI today &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#psi-today&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Taking a step back, let&#39;s look at what the current PageSpeed Insights report
offers. The PSI report includes performance data for both mobile and desktop
devices in individual tabs and suggests how you may improve a page. The key
components of the report in each case are similar and consist of the
following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance Score:&lt;/strong&gt; The performance score appears at the top of the PSI
report and summarizes the overall page performance. This score is determined by
running &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; to
collect and analyze &lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/about#lab&quot; rel=&quot;noopener&quot;&gt;lab
data&lt;/a&gt; about the
page. A score of 90 or above is considered good, 50-90 needs improvement, and
below 50 is poor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Field Data:&lt;/strong&gt; Field data, sourced from the
&lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;CrUX report&lt;/a&gt;
dataset, provides insights into the real-world user experience. The data
includes metrics such as &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; (FCP),
and measures Core Web Vitals  (&lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt; (FID),
&lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt; (LCP), and &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout
Shift&lt;/a&gt; (CLS). Along with the metric values, you can also
see the distribution of pages where the value of a particular metric was Good,
Needs Improvement, or Poor, indicated by green, amber, and red bars,
respectively. The distribution and scores are shown based on page loads for
users in the CrUX dataset. Scores are calculated for the last 28 days and are
not available for new pages where sufficient real-user data may not be
available.&lt;/p&gt;
&lt;img alt=&quot;breakdown of different sections of data in the current PageSpeed Insight report&quot; decoding=&quot;async&quot; height=&quot;497&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/A7xrSBFuqf9puSgBJH4l.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;strong&gt;Origin Summary:&lt;/strong&gt; Users can click on the &lt;em&gt;Show Origin Summary&lt;/em&gt; checkbox to
view the aggregated score for the metrics for all pages served from the same
origin over the last 28 days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lab Data:&lt;/strong&gt; Lab performance score, calculated using Lighthouse, helps debug
performance issues, as it is collected in a controlled environment. The report
shows the performance using metrics like&lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful
Paint&lt;/a&gt;, &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt;,
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/speed-index/&quot; rel=&quot;noopener&quot;&gt;Speed Index&lt;/a&gt;, &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout
Shift&lt;/a&gt;, &lt;a href=&quot;https://web.dev/tti/&quot;&gt;Time to
Interactive&lt;/a&gt;, and &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking
Time&lt;/a&gt;. Each metric is
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/performance-scoring/&quot; rel=&quot;noopener&quot;&gt;scored&lt;/a&gt; and labeled with an icon
indicating Good, Needs improvement, or Poor. This section provides a good
indication of performance bottlenecks pre-release and can help to diagnose
problems, but may not capture real-world issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audits:&lt;/strong&gt; This section lists all the audits run by Lighthouse and lists down
the passed audits along with opportunities for improvement and additional
diagnostic information.&lt;/p&gt;
&lt;h3 id=&quot;challenges-with-the-current-psi-design&quot;&gt;Challenges with the current PSI design &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#challenges-with-the-current-psi-design&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As seen in the screenshot above, the different data points from lab and field
data are not isolated clearly, and developers who are new to PSI may not easily
understand the context of the data and what to do next. This confusion has
resulted in many &amp;quot;How to&amp;quot; blog posts on deciphering the PSI report.&lt;/p&gt;
&lt;p&gt;With the redesign, we hope to make interpreting the report easier for developers
so that they move quickly from generating the PSI report to acting upon the
insights included in it.&lt;/p&gt;
&lt;h2 id=&quot;learn-more&quot;&gt;Learn more &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/whats-new-pagespeed-insights/#learn-more&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For more details on performance tooling updates, watch the keynote for &lt;a href=&quot;https://developer.chrome.com/devsummit/schedule/keynote/&quot; rel=&quot;noopener&quot;&gt;Chrome
Dev Summit 2021&lt;/a&gt;.
We will keep you posted on the release date for PSI and the changes to web.dev/measure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Milica Mihajlija, Philip Walton, Brendan Kenny and
Ewa Gasperowicz for their feedback on this article&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Leena Sohoni</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Elizabeth Sweeny</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimizing resource loading with the Fetch Priority API</title>
    <link href="https://web.dev/fetch-priority/"/>
    <updated>2021-10-20T00:00:00Z</updated>
    <id>https://web.dev/fetch-priority/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 102, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      102
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge 102, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
102
&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari preview, Preview&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;preview&quot; title=&quot;Preview&quot; aria-label=&quot;Preview&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/fetchPriority#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&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; This feature was originally called Priority Hints but was renamed to Fetch Priority after standardization. See &lt;a href=&quot;https://web.dev/fetch-priority/#history&quot;&gt;History&lt;/a&gt; below for more details. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;When a browser parses a web page and begins to discover and download resources such as images, scripts, or CSS, it assigns them a fetch &lt;code&gt;priority&lt;/code&gt; in an attempt to download resources in an optimal order. These priorities can depend on the kind of resource and where it is in the document. For example, in-viewport images may have a &lt;code&gt;High&lt;/code&gt; priority while the priority for early loaded, render-blocking CSS via &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;s in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; could be &lt;code&gt;Very High&lt;/code&gt;. Browsers are pretty good at assigning priorities that work well but may not be optimal in all cases.&lt;/p&gt;
&lt;p&gt;In this article, we&#39;ll discuss the Fetch Priority API and the &lt;code&gt;fetchpriority&lt;/code&gt; HTML attribute, which allow you to hint at the relative priority of a resource (&lt;code&gt;high&lt;/code&gt; or &lt;code&gt;low&lt;/code&gt;). Fetch Priority can help optimize the Core Web Vitals.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A filmstrip view comparing two tests of the Google Flights homepage. At bottom, Fetch Priority are used to boost the priority of the hero image, resulting in a 0.7 second decrease in LCP.&quot; decoding=&quot;async&quot; height=&quot;400&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/UQ60oFwWrVCPbFYx3pJY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Fetch Priority improving Largest Contentful Paint from 2.6&amp;nbsp;s to 1.9&amp;nbsp;s in a test of Google Flights&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A few key areas where Fetch Priority can help:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boost the priority of the LCP image by specifying &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; on the image element, causing LCP to happen sooner.&lt;/li&gt;
&lt;li&gt;Increase the priority of &lt;code&gt;async&lt;/code&gt; scripts using better semantics than the current hack that is commonly used (inserting a &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; for the &lt;code&gt;async&lt;/code&gt; script).&lt;/li&gt;
&lt;li&gt;Decrease the priority of late-body scripts to allow for better sequencing with images.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Historically, developers have had some, but limited, influence over resource priority using &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preload/&quot; rel=&quot;noopener&quot;&gt;preload&lt;/a&gt; and &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;preconnect&lt;/a&gt;. Fetch Priority complements these &lt;a href=&quot;https://www.w3.org/TR/resource-hints/&quot; rel=&quot;noopener&quot;&gt;Resource Hints&lt;/a&gt;, but it&#39;s essential to understand where they all fit in. Preload lets you tell the browser about critical resources you want to load early before they are discovered naturally. This is especially useful for resources that are not easily discovered, such as fonts included in stylesheets, background images, or resources loaded from a script. Preconnect helps warm up connections to cross-origin servers and can help improve metrics like &lt;a href=&quot;https://web.dev/ttfb/&quot;&gt;Time-to-first-byte&lt;/a&gt; and is useful when you know an origin but not necessarily the exact URL of a resource that will be needed.&lt;/p&gt;
&lt;p&gt;Fetch Priority is a markup-based signal (available through the &lt;code&gt;fetchpriority&lt;/code&gt; attribute) that developers can use to indicate the relative priority of a particular resource. You can also use these hints via JavaScript and the &lt;a href=&quot;https://web.dev/introduction-to-fetch/&quot;&gt;Fetch API&lt;/a&gt; with the &lt;code&gt;priority&lt;/code&gt; property to influence the priority of resource fetches made for data. Fetch Priority can also complement preload. Take a Largest Contentful Paint image, which, when preloaded, will still get a low priority. If it is pushed back by other early low-priority resources, using Fetch Priority can help how soon the image gets loaded.&lt;/p&gt;
&lt;p&gt;Fetch Priority is &lt;a href=&quot;https://www.chromestatus.com/feature/5273474901737472&quot; rel=&quot;noopener&quot;&gt;available&lt;/a&gt; in Chrome 101 or later.&lt;/p&gt;
&lt;h2 id=&quot;resource-priority&quot;&gt;Resource priority &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#resource-priority&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The resource download sequence depends on the browser&#39;s assigned priority for every resource on the page. Different factors can affect priority computation logic. For example,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS, fonts, scripts, images, and third-party resources are assigned different priorities.&lt;/li&gt;
&lt;li&gt;The location or order in which you reference resources in the document also affects the priority of resources.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preload/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;preload&lt;/code&gt;&lt;/a&gt; resource hint helps the browser to discover a resource faster and thus load it before the document loads it and affects priority.&lt;/li&gt;
&lt;li&gt;Priority computation changes for &lt;a href=&quot;https://web.dev/efficiently-load-third-party-javascript/#use-async-or-defer&quot;&gt;&lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; scripts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following table considers such factors to show how most resources are currently prioritized and sequenced in Chrome.&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;&amp;nbsp;&lt;/th&gt;
        &lt;th&gt;Layout-blocking&lt;/th&gt;
        &lt;th&gt;Load in layout-blocking phase&lt;/th&gt;
        &lt;th colspan=&quot;3&quot;&gt;Load one-at-a-time in layout-blocking phase&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Blink&lt;br /&gt;Priority&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;VeryHigh&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;VeryLow&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;DevTools&lt;br /&gt;Priority&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Highest&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Lowest&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Main resource&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;CSS*** (early**)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;CSS*** (late**)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;CSS (mismatch)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Script (early** or not from preload scanner)&lt;/td&gt;
        &lt;td&gt;Script (**late)&lt;/td&gt;
        &lt;td&gt;Script (async)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Font&lt;/td&gt;
        &lt;td&gt;Font (preload)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Import&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Image (in viewport)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Image&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Media&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;SVG document&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Prefetch&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;Preload*&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;XSL&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;XHR (sync)&lt;/td&gt;
        &lt;td&gt;XHR/fetch* (async)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&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; * Preload using &lt;code&gt;&amp;quot;as&amp;quot;&lt;/code&gt; or fetch using &lt;code&gt;&amp;quot;type&amp;quot;&lt;/code&gt; use the priority of the type they are requesting (e.g., preload &lt;code&gt;as=&amp;quot;stylesheet&amp;quot;&lt;/code&gt; will use Highest priority). With no &lt;code&gt;&amp;quot;as&amp;quot;&lt;/code&gt;, they will behave like an XHR.&lt;br /&gt; ** &amp;quot;Early&amp;quot; is defined as being requested before any non-preloaded images have been requested (&amp;quot;late&amp;quot; is after).&lt;br /&gt; *** CSS where the media type doesn&#39;t match is not fetched by the preload scanner and is only processed when the main parser reaches it, which usually means it will be fetched very late and with a &amp;quot;late&amp;quot; priority. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The browser downloads resources with the same computed priority in the order they are discovered. You can check the priority assigned to different resources when loading a page under the Chrome Dev Tools &lt;strong&gt;Network&lt;/strong&gt; tab. (Ensure that you include the priority column by right-clicking on the table headings).&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of assets listed in the network tab of Chrome&amp;#x27;s DevTools. The columns read, from left to right: name, status, type, initiator, size, time, and priority.&quot; decoding=&quot;async&quot; height=&quot;263&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Lwm9jwJF5sQ3gQ7PHSs1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Priority for resource &lt;code&gt;type = &amp;quot;font&amp;quot;&lt;/code&gt; on BBC news detail page&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of assets listed in the network tab of Chrome&amp;#x27;s DevTools. The columns read, from left to right: name, status, type, initiator, size, time, and priority.&quot; decoding=&quot;async&quot; height=&quot;175&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/K5U3maOt2TFBbtScW7TY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Priority for resource type = &amp;quot;script&amp;quot; on BBC news detail page&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;when-would-you-need-fetch-priority&quot;&gt;When would you need Fetch Priority? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#when-would-you-need-fetch-priority&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Knowledge of the browser&#39;s prioritization logic provides you with a few existing knobs to tweak the order of downloads. You can&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Place resource tags such as &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; depending on the order you want to download them. Resources with the same priority are generally loaded in the order they are discovered.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/preload-critical-assets/&quot;&gt;Use the &lt;code&gt;preload&lt;/code&gt; resource hint&lt;/a&gt; to download necessary resources earlier, particularly for resources that are not easily discovered early by the browser.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;https://web.dev/efficiently-load-third-party-javascript/#use-async-or-defer&quot;&gt;&lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; to download scripts without blocking other resources.&lt;/li&gt;
&lt;li&gt;Lazy-load below-the-fold content so that the browser can use the available bandwidth for more critical above-the-fold resources.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These techniques help to control the browser&#39;s priority computation, thereby improving performance and &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt;. For example, when a critical background image is preloaded, it can be discovered much earlier, improving the Largest Contentful Paint (&lt;a href=&quot;https://web.dev/lcp/&quot;&gt;LCP&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Sometimes these handles may not be enough to prioritize resources optimally for your application. Here are some of the scenarios where Fetch Priority could be helpful:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You have several above-the-fold images, but all of them need not have the same priority. For example, in an image carousel, only the first visible image needs a higher priority compared to the others.&lt;/li&gt;
&lt;li&gt;Hero images inside the viewport start at a &amp;quot;Low&amp;quot; priority. After the layout is complete, Chrome discovers they are in the viewport and boosts their priority (unfortunately, dev tools only shows the final priority—WebPageTest will show both). This usually adds a significant delay to loading the image. Providing the Fetch Priority in markup lets the image start at a &amp;quot;High&amp;quot; priority and start loading much earlier.&lt;br /&gt;&lt;br /&gt;Note that preload is still required for the early discovery of LCP images included as CSS backgrounds and can be combined with Fetch Priority by including the &lt;code&gt;fetchpriority=&#39;high&#39;&lt;/code&gt; on the preload, otherwise it will still start with the default &amp;quot;Low&amp;quot; priority for images.&lt;/li&gt;
&lt;li&gt;Declaring scripts as &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; tells the browser to load them asynchronously. However, as seen in the figure above, these scripts are also assigned a &amp;quot;low&amp;quot; priority. You may want to bump up their priority while ensuring asynchronous download, particularly for any scripts that are critical for the user experience.&lt;/li&gt;
&lt;li&gt;You may use the JavaScript &lt;a href=&quot;https://web.dev/introduction-to-fetch/&quot;&gt;&lt;code&gt;fetch()&lt;/code&gt;&lt;/a&gt; API to fetch resources or data asynchronously. Fetch is assigned a &amp;quot;High&amp;quot; priority by the browser. There may be situations where you do not want all your fetches to be executed with &amp;quot;High&amp;quot; priority and prefer using different Fetch Priority instead. This can be helpful when running background API calls and mixing them with API calls that are responding to user input, like with autocomplete. The background API calls can be tagged as &amp;quot;Low&amp;quot; priority and the interactive API calls marked as &amp;quot;High&amp;quot; priority.&lt;/li&gt;
&lt;li&gt;The browser assigns CSS and fonts a &amp;quot;High&amp;quot; priority, but all such resources may not be equally important or required for LCP. You can use Fetch Priority to lower the priority of some of these resources.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-fetchpriority-attribute&quot;&gt;The &lt;code&gt;fetchpriority&lt;/code&gt; attribute &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#the-fetchpriority-attribute&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can provide a Fetch Priority using the &lt;code&gt;fetchpriority&lt;/code&gt; HTML attribute. You can use the attribute with &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt;, and &lt;code&gt;script&lt;/code&gt; tags. The attribute allows you to specify the priority for resource types such as CSS, fonts, scripts, and images when downloaded using the supported tags.
The &lt;code&gt;fetchpriority&lt;/code&gt; attribute accepts one of three values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;high&lt;/code&gt;: You consider the resource a high priority and want the browser to prioritize it as long as the browser&#39;s heuristics don&#39;t prevent that from happening.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;low&lt;/code&gt;: You consider the resource a low priority and want the browser to deprioritize it if it&#39;s heuristics permit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;: This is the default value where you don&#39;t have a preference and let the browser decide the appropriate priority.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are a few examples of using the &lt;code&gt;fetchpriority&lt;/code&gt; attribute in markup and the script-equivalent &lt;code&gt;priority&lt;/code&gt; property.&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 comment&quot;&gt;&amp;lt;!-- We don&#39;t want a high priority for this above-the-fold image --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/images/in_viewport_but_not_important.svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;low&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;I&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;m an unimportant image!&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 comment&quot;&gt;&amp;lt;!-- We want to initiate an early fetch for a resource, but also deprioritize it --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/js/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;&quot;&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;&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;&quot;&lt;/span&gt;low&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;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#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 literal-property property&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;low&#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 function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&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;// Trigger a low priority fetch&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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;browser-priority-and-fetchpriority&quot;&gt;Browser priority and &lt;code&gt;fetchpriority&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#browser-priority-and-fetchpriority&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can apply the &lt;code&gt;fetchpriority&lt;/code&gt; attribute to different resources as shown in the following figure to potentially increase or reduce their computed priority. &lt;code&gt;fetchpriority=&amp;quot;auto&amp;quot;&lt;/code&gt; (◉) in each row denotes the default priority for that type of resource.&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;&amp;nbsp;&lt;/th&gt;
        &lt;th&gt;Layout-blocking&lt;/th&gt;
        &lt;th&gt;Load in layout-blocking phase&lt;/th&gt;
        &lt;th colspan=&quot;3&quot;&gt;Load one-at-a-time in layout-blocking phase&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Blink&lt;br /&gt;Priority&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;VeryHigh&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;VeryLow&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;DevTools&lt;br /&gt;Priority&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Highest&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Lowest&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Main Resource&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;CSS*** (early**)&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;CSS*** (late**)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Script (early** or not from preload scanner)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Script*** (late**)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Script (async/defer)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Font&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Font (preload)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Import&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Image (in viewport)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Image&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Media (video/audio)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;SVG document&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;XHR (sync) - deprecated&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;XHR/fetch* (async)&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Preload*&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬆◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;⬇&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Prefetch&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Favicon&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;XSL&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;◉&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&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; * Preload using &lt;code&gt;&amp;quot;as&amp;quot;&lt;/code&gt; or fetch using &lt;code&gt;&amp;quot;type&amp;quot;&lt;/code&gt; use the priority of the type they are requesting (e.g., preload &lt;code&gt;as=&amp;quot;stylesheet&amp;quot;&lt;/code&gt; will use Highest priority). With no &lt;code&gt;&amp;quot;as&amp;quot;&lt;/code&gt;, they will behave like an XHR.&lt;br /&gt; ** &amp;quot;Early&amp;quot; is defined as being requested before any non-preloaded images have been requested (&amp;quot;late&amp;quot; is after).&lt;br /&gt; *** CSS where the media type doesn&#39;t match is not fetched by the preload scanner and is only processed when the main parser reaches it, which usually means it will be fetched very late and with a &amp;quot;late&amp;quot; priority.&lt;br /&gt; ◉: &lt;code&gt;fetchpriority=&amp;quot;auto&amp;quot;&lt;/code&gt;&lt;br /&gt; ⬆: &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;br /&gt; ⬇: &lt;code&gt;fetchpriority=&amp;quot;low&amp;quot;&lt;/code&gt;&lt;br /&gt; Images within the viewport start at &amp;quot;Low&amp;quot; priority and then at layout time are boosted to &amp;quot;High&amp;quot;. By tagging it in markup using &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;, it can start at &amp;quot;High&amp;quot; immediately and load much faster. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Note that &lt;code&gt;fetchpriority&lt;/code&gt; sets the &lt;em&gt;relative priority&lt;/em&gt;—that is it raises or lowers the default priority by an appropriate amount, rather than explicitly setting the priority to &amp;quot;High&amp;quot; or &amp;quot;Low&amp;quot; and the browser decides the relative priority. Often this is &amp;quot;High&amp;quot; or &amp;quot;Low&amp;quot;, but not always. For example, critical CSS with &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; will still retain the &amp;quot;VeryHigh&amp;quot;/&amp;quot;Highest&amp;quot; priority, and using &lt;code&gt;fetchpriority=&amp;quot;low&amp;quot;&lt;/code&gt; on these will still retain the &amp;quot;High&amp;quot; priority—in neither case is the Priority explicitly set to &amp;quot;High&amp;quot; or &amp;quot;Low&amp;quot;.&lt;/p&gt;
&lt;h3 id=&quot;use-cases&quot;&gt;Use cases &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#use-cases&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code&gt;fetchpriority&lt;/code&gt; attribute to address scenarios where you may wish to provide the browser with an extra hint as to what priority to fetch a resource with.&lt;/p&gt;
&lt;h4 id=&quot;increase-the-priority-of-the-lcp-image&quot;&gt;Increase the priority of the LCP image &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#increase-the-priority-of-the-lcp-image&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You can specify &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; to boost the priority of the LCP or other critical images.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lcp-image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;high&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;The following comparison shows the Google Flights page with an LCP background image loaded with and without Fetch Priority. With the priority set to high, the &lt;a href=&quot;https://www.webpagetest.org/video/compare.php?tests=211006_AiDcG3_40871b05d6040112a05be4524565cf5d%2C211006_BiDcHR_bebed947f1b6607f2d97e8a899fdc36b&amp;amp;thumbSize=200&amp;amp;ival=100&amp;amp;end=visual&quot; rel=&quot;noopener&quot;&gt;LCP improved from 2.6s to 1.9s&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;video autoplay=&quot;&quot; controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/1L2RBhCLSnXjCnSlevaDjy3vba73/BCngJfoVOy0YbUz8wFrM.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;An experiment conducted using Cloudflare workers to rewrite the Google Flights page to use Fetch Priority.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;lower-the-priority-of-above-the-fold-images&quot;&gt;Lower the priority of above-the-fold images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#lower-the-priority-of-above-the-fold-images&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You can use &lt;code&gt;fetchpriority=&amp;quot;low&amp;quot;&lt;/code&gt; to lower the priority of above-the-fold images that may not be important for example in an image carousel.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;carousel&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;img/carousel-1.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;img/carousel-2.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;low&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;img/carousel-3.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;low&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;img/carousel-4.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;low&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In an earlier experiment with the &lt;a href=&quot;https://github.com/google/oodle-demo&quot; rel=&quot;noopener&quot;&gt;Oodle&lt;/a&gt; app, we used this to lower the priority of images that do not appear on load. It helped to cut down the load time by 2 seconds.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A side-by-side comparison of Fetch Priority when used on the Oodle app&amp;#x27;s image carousel. On the left, the browser sets default priorities for carousel images, but downloads and paints those images around two seconds slower than the example on the right, which sets a higher priority on only the first carousel image.&quot; decoding=&quot;async&quot; height=&quot;460&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/Tn4OkGpqPbrSQtd1j3GV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;lower-the-priority-of-preloaded-resources&quot;&gt;Lower the priority of preloaded resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#lower-the-priority-of-preloaded-resources&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To stop preloaded resources from competing with other critical resources, you could provide a hint to reduce their priority. You can use this technique with images, scripts, and CSS.&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 comment&quot;&gt;&amp;lt;!-- Lower priority only for non-critical preloaded scripts --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;&quot;&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;critical-script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/js/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;&quot;&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;&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;&quot;&lt;/span&gt;low&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 comment&quot;&gt;&amp;lt;!-- Preload CSS without blocking other resources --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;&quot;&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;theme.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;low&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;onload&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rel&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;stylesheet&#39;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;reprioritize-scripts&quot;&gt;Reprioritize scripts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#reprioritize-scripts&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Scripts required to make some parts of the page interactive are essential but should not block other resources. You can mark these as async with high priority.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async_but_important.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Scripts cannot be marked as async if they rely on specific DOM states. However if they are lower down on the page, they may be downloaded with a lower priority as shown.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;blocking_but_unimportant.js&lt;span class=&quot;token punctuation&quot;&gt;&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;&quot;&lt;/span&gt;low&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;lower-the-priority-for-non-critical-data-fetches&quot;&gt;Lower the priority for non-critical data fetches &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#lower-the-priority-for-non-critical-data-fetches&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The browser executes &lt;code&gt;fetch&lt;/code&gt; with a high priority. If you have multiple fetches that may be fired simultaneously, you can use the high default priority for the more critical data fetches and lower it for less critical data.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Important validation data (high by default)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; authenticate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/user&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Less important content data (suggested low)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; suggestedContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/content/suggested&#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 literal-property property&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;low&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;fetch-priority-implementation-notes&quot;&gt;Fetch Priority implementation notes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#fetch-priority-implementation-notes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fetch Priority can improve performance in specific use cases, as discussed above. There are some things to be aware of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;fetchpriority&lt;/code&gt; attribute is a hint and not a directive. The browser will try to respect the developer&#39;s preference. It is also possible that the browser will apply its preferences for resource priority as deemed necessary in case of conflicts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fetch Priority should not be confused with a preload. They are both distinct because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preload is a mandatory fetch and not a hint.&lt;/li&gt;
&lt;li&gt;Preload allows the browser to discover the resource early, but it will still fetch it with the default priority. Conversely, Fetch Priority does not aid discoverability, but does allow you to increase or decrease the fetch priority.&lt;/li&gt;
&lt;li&gt;It is easier to observe and measure the effects of a preload.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fetch Priority can complement preloads by increasing the granularity of prioritization. If you had already specified a preload as one of the first items in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; for an LCP image, then a &lt;code&gt;high&lt;/code&gt; Fetch Priority may not result in significant gains. However, if the preload was after other resources, then a &lt;code&gt;high&lt;/code&gt; Fetch Priority can improve the LCP. If a critical image is a CSS background image, you should preload it with &lt;code&gt;fetchpriority = &amp;quot;high&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The noticeable gains due to prioritization will be more relevant in environments where more resources contend for the available network bandwidth. This is common for HTTP/1.x connections where parallel downloads are not possible or in low bandwidth HTTP/2 connections. Prioritization can resolve bottlenecks in these conditions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CDNs do &lt;a href=&quot;https://github.com/andydavies/http2-prioritization-issues#cdns--cloud-hosting-services&quot; rel=&quot;noopener&quot;&gt;not uniformly implement HTTP/2 prioritization&lt;/a&gt;. Even if the browser communicates the priority suggested using Fetch Priority; the CDN may not reprioritize resources in the required order. This makes testing of Fetch Priority difficult. The priorities are applied both internally within the browser and with protocols that support prioritization (HTTP/2 and HTTP/3). It is still worth using even for just the internal browser prioritization independent of CDN or origin support, as that will often change when resources are requested by the browser—for example low priority resources like images are often held back from being requested while the browser processes the critical &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; items.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It may not be possible to introduce Fetch Priority as a best practice in your initial design. It is an optimization that you can apply later in the development cycle. You can check the priorities being assigned to different resources on the page, and if they do not match your expectations, you could introduce Fetch Priority for further optimization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;using-preload-after-chrome-95&quot;&gt;Using Preload after Chrome 95 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#using-preload-after-chrome-95&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Fetch Priority feature was available for trial in Chrome 73 to 76 but was not released due to prioritization issues with preloads fixed in Chrome 95. Prior to Chrome 95, requests issued via &lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt; always start before other requests seen by the preload scanner, even if the other requests have a higher priority.&lt;/p&gt;
&lt;p&gt;With the fix in Chrome 95 and the enhancement for Fetch Priority, we hope that developers will start using preload for its &lt;a href=&quot;https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/#loading-of-late-discovered-resources&quot; rel=&quot;noopener&quot;&gt;intended purpose&lt;/a&gt;—to preload resources not detected by the parser (fonts, imports, background LCP images). The placement of the &lt;code&gt;preload&lt;/code&gt; hint will affect when the resource is preloaded. Some key points on using preload are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Including the preload in HTTP headers will cause it to jump ahead of everything else.&lt;/li&gt;
&lt;li&gt;Generally, preloads will load in the order the parser gets to them for anything above &amp;quot;Medium&amp;quot; priority—so be careful if you are including preloads at the beginning of the HTML.&lt;/li&gt;
&lt;li&gt;Font preloads will probably work best towards the end of the head or beginning of the body.&lt;/li&gt;
&lt;li&gt;Import preloads (dynamic &lt;code&gt;import()&lt;/code&gt; or &lt;code&gt;modulepreload&lt;/code&gt;) should be done after the script tag that needs the import (so the actual script gets loaded/parsed first). Basically, if the script tag loads a script that will trigger the load of dependencies, make sure the &lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt; for the dependencies is after the parent script tag, otherwise the dependencies may end up loading before the main script. In the proper order, the main script can be parsed/eval&#39;d while the dependencies are loading.&lt;/li&gt;
&lt;li&gt;Image preloads will have a &amp;quot;Low&amp;quot; priority (without Fetch Priority) and should be ordered relative to async scripts and other low or lowest priority tags.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;history&quot;&gt;History &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#history&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fetch Priority was first experimented with in Chrome as an origin trial in 2018 and then again in 2021 using the &lt;code&gt;importance&lt;/code&gt; attribute. At that time it was known as &lt;a href=&quot;https://github.com/WICG/priority-hints&quot; rel=&quot;noopener&quot;&gt;Priority Hints&lt;/a&gt;. The interface has since changed to &lt;code&gt;fetchpriority&lt;/code&gt; for HTML and &lt;code&gt;priority&lt;/code&gt; for JavaScript&#39;s Fetch API as part of the web standards process. To reduce confusion we now refer to this API as Fetch Priority.&lt;/p&gt;
&lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#browser-compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 102, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      102
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge 102, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
102
&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari preview, Preview&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;preview&quot; title=&quot;Preview&quot; aria-label=&quot;Preview&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/fetchPriority#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;As of this writing, Fetch Priority is only available in Chromium-based browsers. Other browser engines or earlier versions of Chromium browsers will ignore the attribute and use their default prioritization heuristics. Until another browser implements Fetch Priority, you may notice some references—&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/fetchPriority&quot; rel=&quot;noopener&quot;&gt;such as MDN&lt;/a&gt;—mark this as &lt;a href=&quot;https://developer.mozilla.org/docs/MDN/Writing_guidelines/Experimental_deprecated_obsolete#experimental&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;Experimental&lt;/em&gt;&lt;/a&gt;, however Fetch Priority is now standardized and included in the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/urls-and-fetching.html#fetch-priority-attributes&quot; rel=&quot;noopener&quot;&gt;HTML living standard&lt;/a&gt; and &lt;a href=&quot;https://fetch.spec.whatwg.org/#request-priority&quot; rel=&quot;noopener&quot;&gt;Fetch living standard&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-priority/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Developers are likely to be interested in Fetch Priority with the fixes in preload behavior and the recent focus on Core Web Vitals and LCP. They now have additional knobs available to achieve their desired loading sequence.&lt;/p&gt;
</content>
    <author>
      <name>Leena Sohoni</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Patrick Meenan</name>
    </author><author>
      <name>Barry Pollard</name>
    </author>
  </entry>
  
  <entry>
    <title>Best practices for using third-party embeds</title>
    <link href="https://web.dev/embed-best-practices/"/>
    <updated>2021-10-05T00:00:00Z</updated>
    <id>https://web.dev/embed-best-practices/</id>
    <content type="html" mode="escaped">&lt;p&gt;Many sites use third-party embeds to create an engaging user experience by delegating some sections of a web page to another content provider. The most common examples of third-party content embeds are video players, social-media feeds, maps, and advertisements.&lt;/p&gt;
&lt;p&gt;Third-party content can impact the performance of a page in many ways. It can be render-blocking, contend with other critical resources for network and bandwidth, or affect the Core Web Vitals metrics. Third-party embeds may also cause layout shifts as they load. This article discusses performance best practices that you can use when loading third-party embeds, efficient loading techniques, and the Layout Shift Terminator tool that helps reduce layout shifts for popular embeds.&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; It&#39;s best to use the techniques described in this post to load only offscreen or non-primary page content. This ensures that all the critical content gets indexed by &lt;a href=&quot;https://developers.google.com/search/docs/advanced/javascript/lazy-loading&quot;&gt;search engines&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;what-is-an-embed&quot;&gt;What is an embed &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#what-is-an-embed&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A third-party embed is any content displayed on your site that is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not authored by you&lt;/li&gt;
&lt;li&gt;Served from third-party servers&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Multiple offscreen embeds are shown, which could be lazy-loaded&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/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/QfPvNJo9yN6IcxvWqYWI.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Embeds are frequently used in the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Websites related to sports, news, entertainment, and fashion use videos to augment textual content.&lt;/li&gt;
&lt;li&gt;Organizations with active Twitter or social media accounts embed feeds from these accounts to their web pages to engage and reach out to more people.&lt;/li&gt;
&lt;li&gt;Restaurant, park, and event venue pages often embed maps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party embeds are typically loaded in &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/iframe&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;&lt;/a&gt; elements on the page. Third-party providers offer HTML snippets often consisting of an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; that pulls in a page composed of markup, scripts, and stylesheets. Some providers also use a script snippet that dynamically injects an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; to pull other content in. This can make the third-party embeds heavy and affect the performance of the page by delaying its first-party content.&lt;/p&gt;
&lt;h2 id=&quot;performance-impact-of-third-party-embeds&quot;&gt;Performance impact of third-party embeds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#performance-impact-of-third-party-embeds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many popular embeds include over 100 KB of JavaScript, sometimes even going up to 2 MB. They take more time to load and keep the main thread busy when executing. Performance monitoring tools such as &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; and &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt; help to &lt;a href=&quot;https://web.dev/identify-slow-third-party-javascript/&quot;&gt;measure the impact of third-party embeds on performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/third-party-summary/&quot; rel=&quot;noopener&quot;&gt;Reduce the impact of third-party code&lt;/a&gt; Lighthouse audit shows the list of third-party providers a page uses, with size and main-thread blocking time. The audit is available through Chrome DevTools under the Lighthouse tab.&lt;/p&gt;
&lt;p&gt;It is a good practice to periodically audit the performance impact of your embeds and third-party code because embed source code may change. You can use this opportunity to remove any redundant code.&lt;/p&gt;
&lt;img alt=&quot;Reduce the impact of third-party code&quot; decoding=&quot;async&quot; height=&quot;738&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/WektrXQsgQPMWy2hxQ4E.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;loading-best-practices&quot;&gt;Loading best practices &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#loading-best-practices&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Third-party embeds can negatively impact performance, but they also offer important functionalities. To efficiently use third-party embeds and reduce their performance impact, follow the guidelines below.&lt;/p&gt;
&lt;h3 id=&quot;script-ordering&quot;&gt;Script ordering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#script-ordering&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a well-designed page, the key first-party content will be the focus of the page, while the third-party embeds will occupy side-bars or appear after the first-party content.&lt;/p&gt;
&lt;p&gt;For the best user experience, the main content should load quickly and before any other supporting content. For example, the news text on a news page should load before embeds for a Twitter feed or advertisements.&lt;/p&gt;
&lt;p&gt;Requests for third-party embeds can get in the way of loading first-party content, so the position of a third-party script tag is important. Scripts can affect the loading sequence because the DOM construction pauses while scripts are executed. Place third-party script tags after the key first-party tags and &lt;a href=&quot;https://web.dev/efficiently-load-third-party-javascript/#use-async-or-defer&quot;&gt;use &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; attributes to load them asynchronously.&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Order of Things&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/assets/application.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;index.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com/3p-library.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&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;lazy-loading&quot;&gt;Lazy-loading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since third-party content usually comes after the primary content, it may not be visible in the viewport when the page loads. In that case, downloading third-party resources may be deferred until the user scrolls down to that part of the page. This not only helps optimize the initial page load but also reduces the download costs for users on fixed data plans and slow network connections.&lt;/p&gt;
&lt;p&gt;Delaying the download of content until it is actually needed is called &lt;a href=&quot;https://web.dev/lazy-loading-best-practices/&quot;&gt;lazy-loading&lt;/a&gt;. Depending on the requirements and the type of embed, you can use different lazy-loading techniques explained below.&lt;/p&gt;
&lt;h4 id=&quot;native-lazy-loading-for-lessiframegreater&quot;&gt;Native lazy-loading for &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#native-lazy-loading-for-lessiframegreater&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For third-party embeds loaded through &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; elements, you can use browser-level lazy-loading to defer loading offscreen iframes until users scroll near them. The &lt;a href=&quot;https://web.dev/iframe-lazy-loading/&quot;&gt;loading attribute for &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; is available in Chrome 77&lt;/a&gt; and above and has &lt;a href=&quot;https://caniuse.com/loading-lazy-attr&quot; rel=&quot;noopener&quot;&gt;also been introduced&lt;/a&gt; to other Chromium-based browsers.&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&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;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;600&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;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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 loading attribute supports the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lazy&lt;/code&gt;: Indicates that the browser should defer loading the iframe. The browser will load the iframe when it is nearing the viewport. Use if the iframe is a good candidate for lazy-loading.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager&lt;/code&gt;: Loads the iframe immediately. Use if the iframe is not a good candidate for lazy-loading. If the &lt;code&gt;loading&lt;/code&gt; attribute has not been specified, this is the default behavior—except in &lt;a href=&quot;https://support.google.com/chrome/answer/2392284?hl=en&amp;amp;co=GENIE.Platform%3DAndroid&quot; rel=&quot;noopener&quot;&gt;Lite mode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;: The browser determines whether to lazy-load this frame.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Browsers that don’t support the &lt;code&gt;loading&lt;/code&gt; attribute ignore it, so you can apply native lazy-loading as a progressive enhancement. Browsers that support the attribute may have different implementations for the &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;distance-from-viewport&lt;/a&gt; threshold (the distance at which the iframe starts loading).&lt;/p&gt;
&lt;p&gt;Following are some ways in which you can lazy load iframes for different types of embeds.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;YouTube videos: To lazy-load a YouTube video player iframe,  include the &lt;code&gt;loading&lt;/code&gt; attribute to the embed code provided by YouTube. Lazy loading the YouTube embed can save approximately 500 KB on the initial page load.&lt;/li&gt;
&lt;/ul&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/aKydtOXW8mI&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;560&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;315&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;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;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;YouTube video player&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;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;accelerometer; autoplay; clipboard-write;&lt;br /&gt;            encrypted-media; gyroscope; picture-in-picture&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;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;ul&gt;
&lt;li&gt;Google Maps: To lazy-load a Google Map iframe, include the &lt;code&gt;loading&lt;/code&gt; attribute in the code for the iframe embed generated by the &lt;a href=&quot;https://developers.google.com/maps/documentation/embed/get-started&quot; rel=&quot;noopener&quot;&gt;Google Maps Embed API&lt;/a&gt;. Following is an example of the code with a placeholder for the Google Cloud API key.&lt;/li&gt;
&lt;/ul&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.google.com/maps/embed/v1/place?key=API_KEY&amp;amp;q=PLACE_ID&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;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;450&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;border&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 attr-name&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;iframe&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;lazysizes-library&quot;&gt;lazysizes library &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#lazysizes-library&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Because browsers use an embed’s distance-from-viewport, in addition to signals like &lt;a href=&quot;https://googlechrome.github.io/samples/network-information/&quot; rel=&quot;noopener&quot;&gt;effective connection type&lt;/a&gt; and Lite-mode, to decide when an iframe should be loaded, native lazy-loading can be inconsistent. If you need better control on the distance thresholds or you want to provide a consistent lazy-loading experience across browsers, you can use the &lt;a href=&quot;https://github.com/aFarkas/lazysizes&quot; rel=&quot;noopener&quot;&gt;lazysizes&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aFarkas/lazysizes&quot; rel=&quot;noopener&quot;&gt;lazysizes&lt;/a&gt; is a fast, SEO-friendly lazy loader for both images and iframes. Once you have downloaded the component, it can be used with an iframe for a YouTube embed as follows.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazysizes.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/aKydtOXW8mI&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;560&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;315&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;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;lazyload&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;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;YouTube video player&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;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;accelerometer; autoplay; clipboard-write;&lt;br /&gt;        encrypted-media; gyroscope; picture-in-picture&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;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;Similarly, lazysizes may be used with iframes for other third-party embeds.&lt;/p&gt;
&lt;p&gt;Note that lazysizes uses the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Intersection_Observer_API&quot; rel=&quot;noopener&quot;&gt;Intersection Observer API&lt;/a&gt; to detect when an element becomes visible.&lt;/p&gt;
&lt;h4 id=&quot;using-data-lazy-in-facebook&quot;&gt;Using data-lazy in Facebook &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#using-data-lazy-in-facebook&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Facebook provides different types of &lt;a href=&quot;https://developers.facebook.com/docs/plugins&quot; rel=&quot;noopener&quot;&gt;social plugins&lt;/a&gt; that can be embedded. This includes posts, comments, videos, and the most popular &lt;em&gt;Like&lt;/em&gt; button. All plugins include a setting for &lt;code&gt;data-lazy&lt;/code&gt;. Setting it to &lt;code&gt;true&lt;/code&gt; ensures that the plugin will use the browser&#39;s lazy-loading mechanism by setting the &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; iframe attribute.&lt;/p&gt;
&lt;h4 id=&quot;lazy-loading-instagram-feeds&quot;&gt;Lazy-loading Instagram feeds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#lazy-loading-instagram-feeds&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Instagram provides a block of markup and a script as part of the embed. The script injects an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; into the page. Lazy-loading this &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; can improve performance as the embed can be over 100 KB gzipped in size. Many Instagram plugins for WordPress sites like &lt;a href=&quot;https://wordpress.org/plugins/instagram-widget-by-wpzoom/&quot; rel=&quot;noopener&quot;&gt;WPZoom&lt;/a&gt; and &lt;a href=&quot;https://www.mapledesign.co.uk/tech-blog/elfsight-instagram-feed-performance/&quot; rel=&quot;noopener&quot;&gt;Elfsight&lt;/a&gt; provide the lazy-loading option.&lt;/p&gt;
&lt;h3 id=&quot;replace-embeds-with-facades&quot;&gt;Replace embeds with facades &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#replace-embeds-with-facades&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While interactive embeds add value to the page, many users may not interact with them. For example, not every user browsing a restaurant page will click, expand, scroll, and navigate the map embed. Similarly, not every user to a telecom service providers page will interact with the chatbot. In these cases, you can avoid loading or lazy-loading the embed altogether by displaying a facade in its place.&lt;/p&gt;
&lt;div class=&quot;switcher&quot;&gt;
  &lt;figure&gt;
    &lt;figcaption&gt;
      A map embed with a zoom in and out feature.
    &lt;/figcaption&gt;
    &lt;img alt=&quot;A map embed&quot; decoding=&quot;async&quot; height=&quot;725&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/Cn0x7aeqCw7M0X5b4L1P.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure&gt;
    &lt;figcaption&gt;
      A map facade that is an image.
    &lt;/figcaption&gt;
    &lt;img alt=&quot;A map facade&quot; decoding=&quot;async&quot; height=&quot;541&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/f8z9MfvgIFiBkCLA1Qud.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/&quot; rel=&quot;noopener&quot;&gt;facade&lt;/a&gt; is a static element that looks similar to the actual embedded third-party but is not functional and, therefore, much less taxing on the page load. Following are a few strategies to load such embeds optimally while still providing some value to the user.&lt;/p&gt;
&lt;h4 id=&quot;use-static-images-as-facades&quot;&gt;Use static images as facades &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#use-static-images-as-facades&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Static images can be used instead of map embeds where you might not need to make the map interactive. You can zoom in on the area of interest on the map, capture an image, and use this instead of the interactive map embed. You can also use DevTools &lt;strong&gt;Capture node screenshot&lt;/strong&gt; functionality to capture a screenshot of the embedded &lt;code&gt;iframe&lt;/code&gt; element, as shown below.&lt;/p&gt;
&lt;img alt=&quot;Capture node screenshot&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 400px) 400px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EJvMAEUmF3QNUDGBgfNR.png?auto=format&amp;w=800 800w&quot; width=&quot;400&quot; /&gt;
&lt;p&gt;DevTools captures the image as a  &lt;code&gt;png&lt;/code&gt;, but you can also consider converting it to &lt;code&gt;&lt;a href=&quot;https://web.dev/serve-images-webp/&quot;&gt;WebP format for better performance&lt;/a&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;use-dynamic-images-as-facades&quot;&gt;Use dynamic images as facades &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#use-dynamic-images-as-facades&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This technique allows you to generate images corresponding to an interactive embed at run time. Following are some of the tools that allow you to generate static versions of embeds on your pages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maps Static API&lt;/strong&gt;: The Google &lt;a href=&quot;https://developers.google.com/maps/documentation/maps-static/overview&quot; rel=&quot;noopener&quot;&gt;Maps Static API&lt;/a&gt; service generates a map based on the URL parameters included in a standard HTTP request and returns the map as an image you can display on your web page. The URL needs to include the Google Maps API key and must be placed in the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag on the page as the &lt;code&gt;src&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://staticmapmaker.com/google/&quot; rel=&quot;noopener&quot;&gt;Static map maker&lt;/a&gt; tool helps to configure the parameters required for the URL and gives you the code for the image element in real-time.&lt;/p&gt;
&lt;p&gt;The following snippet shows code for an image with the source set to a Maps Static API URL. It has been included in a link tag that ensures that the actual map can be accessed by clicking on the image. (Note: API key attribute is not included in the url)&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.google.com/maps/place/Albany,+NY/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://maps.googleapis.com/maps/api/staticmap?center=Albany,+NY&amp;amp;zoom=13&amp;amp;scale=1&amp;amp;size=600x300&amp;amp;maptype=roadmap&amp;amp;format=png&amp;amp;visual_refresh=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;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;Google Map of Albany, NY&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Twitter screenshots&lt;/strong&gt;: Similar to map screenshots, this concept allows you to dynamically embed a Twitter screenshot instead of the live feed. &lt;a href=&quot;https://tweetpik.com/&quot; rel=&quot;noopener&quot;&gt;Tweetpik&lt;/a&gt; is one of the tools that can be used to take screenshots of tweets. Tweetpik API accepts the URL of the tweet and returns an image with its contents. The API also accepts parameters to customize the background, colors, borders, and dimensions of the image.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;use-click-to-load-to-enhance-facades&quot;&gt;Use click-to-load to enhance facades &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#use-click-to-load-to-enhance-facades&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The click-to-load concept combines lazy-loading and facades. The page initially loads with the facade. When the user interacts with the static placeholder by clicking on it, the third-party embed is loaded. This is also known as the &lt;a href=&quot;https://addyosmani.com/blog/import-on-interaction/&quot; rel=&quot;noopener&quot;&gt;import on interaction&lt;/a&gt; pattern and can be implemented using the following steps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On page load: Facade or static element is included on the page.&lt;/li&gt;
&lt;li&gt;On mouseover: Facade preconnects to the third-party embed provider.&lt;/li&gt;
&lt;li&gt;On click: The facade is replaced by the third-party product.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Facades may be used with third-party embeds for video players, chat widgets, authentication services, and social media widgets. YouTube video embeds that are just images with a play button are facades that we come across frequently. The actual video loads only when you click on the image.&lt;/p&gt;
&lt;p&gt;You can build a custom click-to-load facade using the &lt;em&gt;import on interaction&lt;/em&gt; pattern or use one of the following open source facades available for different types of embeds.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;YouTube facade&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paulirish/lite-youtube-embed&quot; rel=&quot;noopener&quot;&gt;Lite-youtube-embed&lt;/a&gt; is a recommended facade for the YouTube player, which looks like the real player but is 224 times faster. It can be used by downloading the script and stylesheet and then using the &lt;code&gt;&amp;lt;lite-youtube&amp;gt;&lt;/code&gt; tag in HTML or JavaScript. Custom player parameters supported by YouTube may be included through the &lt;code&gt;params&lt;/code&gt; attribute.&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;lite-youtube&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;videoid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ogfYd705cRs&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;playlabel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Play: Keynote (Google I/O &lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;18)&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;lite-youtube&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;Following is a comparison between the lite-youtube-embed and the actual embed.&lt;/p&gt;
&lt;div class=&quot;switcher&quot;&gt;
  &lt;figure&gt;
    &lt;img alt=&quot;Lite YouTube embed&quot; decoding=&quot;async&quot; height=&quot;521&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/EcTxjLs9SUb1ofALN8rA.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
    &lt;figcaption&gt;
      A lite-YouTube embed
    &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure&gt;
    &lt;img alt=&quot;Actual YouTube embed&quot; decoding=&quot;async&quot; height=&quot;502&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/cYG1NJqM8ZoLkYOi6xFJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
    &lt;figcaption&gt;
      A YouTube embed
    &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Other similar facades available for YouTube and Vimeo players are &lt;a href=&quot;https://github.com/justinribeiro/lite-youtube&quot; rel=&quot;noopener&quot;&gt;lite-youtube&lt;/a&gt;, &lt;a href=&quot;https://github.com/luwes/lite-vimeo-embed&quot; rel=&quot;noopener&quot;&gt;lite-vimeo-embed&lt;/a&gt;, and &lt;a href=&quot;https://github.com/slightlyoff/lite-vimeo&quot; rel=&quot;noopener&quot;&gt;lite-vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chat widget facade&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/calibreapp/react-live-chat-loader&quot; rel=&quot;noopener&quot;&gt;React-live-chat-loader&lt;/a&gt; loads a button that looks like a chat embed instead of the embed itself. It can be used with various chat provider platforms such as Intercom, Help Scout, Messenger, and so on. The look-alike widget is much lighter than the chat-widget and loads faster. It can be replaced by the actual chat widget when the user hovers or clicks on the button or if the page has been idle for a long time. The &lt;a href=&quot;https://wildbit.com/blog/2020/09/30/getting-postmark-lighthouse-performance-score-to-100&quot; rel=&quot;noopener&quot;&gt;Postmark case study&lt;/a&gt; explains how they implemented react-live-chat-loader and performance improvements they achieved.&lt;/p&gt;
 &lt;img alt=&quot;Postmark chat widget&quot; decoding=&quot;async&quot; height=&quot;389&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/XyJON43TV8h1qWNZV1Ev.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;remove-or-replace-embeds-with-links&quot;&gt;Remove or replace embeds with links &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#remove-or-replace-embeds-with-links&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you find that some third-party embeds result in poor loading performance and using any of the techniques above is not an option, the simplest thing that you can do is remove the embed entirely. If you still want your users to be able to access the content in the embed, you can provide a link to it with &lt;code&gt;target=&amp;quot;_blank&amp;quot;&lt;/code&gt; so that the user can click and view it in another tab.&lt;/p&gt;
&lt;h2 id=&quot;layout-stability&quot;&gt;Layout stability &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#layout-stability&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While dynamically loading embedded content can improve the loading performance of a page, it can sometimes cause unexpected movement of page content. This is known as layout shift.&lt;/p&gt;
&lt;p&gt;Since visual stability is important to guarantee a smooth user experience, &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt; measures how often those shifts happen and how disruptive they are.&lt;/p&gt;
&lt;p&gt;Layout shifts can be avoided by reserving space during page load for elements that are going to be dynamically loaded later. The browser can determine the space to be reserved if it knows the width and height of the elements. You can ensure this by specifying the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes of iframes or by setting a fixed size for static elements where the third-party embed will be loaded. For example, an iframe for a YouTube embed should have width and height specified as follows.&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/aKydtOXW8mI&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;560&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;315&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;iframe&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;Popular embeds like YouTube, Google Maps, and Facebook provide the embed code with size attributes specified. However, there may be providers who do not include this. For example, this code snippet does not indicate the dimensions of the resulting embed.&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter-timeline&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://twitter.com/ChannelNewsAsia?ref_src=twsrc%5Etfw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-tweet-limit&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;Tweets by ChannelNewsAsia&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://platform.twitter.com/widgets.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can use DevTools to inspect the injected &lt;code&gt;iframe &lt;/code&gt;after this page is rendered. As seen in the following snippet, the height of the injected iframe is fixed while the width is specified in percentage.&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;iframe&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;twitter-widget-0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scrolling&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allowtransparency&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;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;twitter-timeline twitter-timeline-rendered&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;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; static&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; visible&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1000px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 180px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&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; 200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 6238.31px&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 attr-name&quot;&gt;data-widget-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;profile:ChannelNewsAsia&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;Twitter Timeline&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;iframe&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 information can be used to set the size of the containing element to ensure that the container does not expand on loading the feed and there is no layout shift. Following snippet may be used to fix the size of the embed included previously.&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 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;.twitterfeed&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; table-cell&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token property&quot;&gt;vertical-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;.twitter-timeline&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400px &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;twitterfeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter-timeline&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://twitter.com/ChannelNewsAsia?ref_src=twsrc%5Etfw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-tweet-limit&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;Tweets by ChannelNewsAsia&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://platform.twitter.com/widgets.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;h3 id=&quot;layout-shift-terminator&quot;&gt;Layout Shift Terminator &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#layout-shift-terminator&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since third-party embeds often omit the dimensions (width, height) for the final content they render, they can cause significant layout shifts on a page. This problem can be tricky to address without manually inspecting the final sizes using DevTools at a variety of different viewport sizes.&lt;/p&gt;
&lt;p&gt;Now there’s an automated tool, &lt;a href=&quot;https://googlechromelabs.github.io/layout-shift-terminator/&quot; rel=&quot;noopener&quot;&gt;Layout Shift Terminator&lt;/a&gt;, that can help you reduce layout shifts from popular embeds, such as from Twitter, Facebook, and other providers.&lt;/p&gt;
&lt;p&gt;Layout Shift Terminator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loads the embed client-side in an iframe.&lt;/li&gt;
&lt;li&gt;Resizes the iframe to various popular viewport sizes.&lt;/li&gt;
&lt;li&gt;For each popular viewport, captures the dimensions of the embed to later generate media queries and container queries.&lt;/li&gt;
&lt;li&gt;Sizes a min-height wrapper around the embed markup using media queries (and container queries) until the embed initializes (after which the min-height styles are removed).&lt;/li&gt;
&lt;li&gt;Generates an optimized embed snippet that can be copy/pasted where you would otherwise be including the embed in your page.&lt;/li&gt;
&lt;/ul&gt;
 &lt;img alt=&quot;Layour shift Terminal&quot; decoding=&quot;async&quot; height=&quot;740&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/lJrW6vxuf1G80XUmvXBT.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Try out the Layout Shift Terminator, and feel free to leave any feedback on &lt;a href=&quot;https://github.com/GoogleChromeLabs/layout-shift-terminator&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt;. The tool is in a beta state and aims to improve over time with further refinements.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/embed-best-practices/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Third-party embeds can provide a lot of value to users, but as the number and size of embeds on a page increases, performance can suffer. That’s why it is necessary to measure, judge, and use appropriate loading strategies for embeds based on their position, relevance, and potential users&#39; needs.&lt;/p&gt;
</content>
    <author>
      <name>Leena Sohoni</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Katie Hempenius</name>
    </author>
  </entry>
  
  <entry>
    <title>Core Web Vitals workflows with Google tools</title>
    <link href="https://web.dev/vitals-tools/"/>
    <updated>2021-08-09T00:00:00Z</updated>
    <id>https://web.dev/vitals-tools/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt; are a set of metrics that assess the user experience on criteria such as load performance, responsiveness to user input, and layout stability.&lt;/p&gt;
&lt;p&gt;A workflow for improving Core Web Vitals for your website will be explored in this guide, but where that workflow begins depends on whether you&#39;re collecting your own field data. Where it ends may depend on which of Google&#39;s tools you&#39;ll find useful in diagnosing and fixing user experience problems.&lt;/p&gt;
&lt;h2 id=&quot;core-web-vitals-are-best-measured-in-the-field&quot;&gt;Core Web Vitals are best measured in the field &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#core-web-vitals-are-best-measured-in-the-field&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Core Web Vitals are specifically designed to measure how users experience your website—they are &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/&quot;&gt;user centric metrics&lt;/a&gt;. Lab-based tools such as Lighthouse are diagnostic tools to highlight potential performance problems and best practices. Lab-based tools are run under certain, predefined conditions and may not reflect the real-life Core Web Vitals measurements your users experience.&lt;/p&gt;
&lt;aside class=&quot;aside flow color-secondary-box-text bg-secondary-box-bg&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;Highlighter pen&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;M10.22 9.49l-5.91 6c-.77.8-.7 2.05.08 2.85L.77 22h5.68l.74-.75c.78.81 1.95.86 2.73.05l5.96-6.05-5.66-5.76zm12.46-4l-2.82-2.87c-.78-.8-2.07-.84-2.84-.04l-5.75 5.85 5.66 5.75 5.69-5.78c.77-.81.83-2.11.06-2.91z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Key Term&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#lab-data&quot;&gt;&lt;strong&gt;Lab data&lt;/strong&gt;&lt;/a&gt; describes how &lt;em&gt;hypothetical&lt;/em&gt; users &lt;em&gt;may&lt;/em&gt; experience your website. &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#field-data&quot;&gt;&lt;strong&gt;Field data&lt;/strong&gt;&lt;/a&gt; describes how &lt;em&gt;real&lt;/em&gt; users &lt;em&gt;actually&lt;/em&gt; experienced your website. Field data is also known as Real User Monitoring (RUM), and is typically collected by monitoring real user experiences using JavaScript on the pages they load, and reporting various metrics to an analytics solution. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;For example, Lighthouse is a lab-based tool that runs tests with simulated throttling in a simulated desktop or mobile environment. While such simulations of slower network and device conditions are helpful when trying to diagnose performance problems, &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/&quot;&gt;they&#39;re just a single slice&lt;/a&gt; of the large variety in network conditions and device capabilities, and so may not reflect what users on your sites are experiening.&lt;/p&gt;
&lt;p&gt;Lab-based tools like Lighthouse also typically do a &amp;quot;cold load&amp;quot; of a webpage as a totally new visitor. This is often the slowest load, but in real life, visitors may have some assets cached if they have visited before, or when they are browsing around the site. New visitors, and tools, also may experience the site differently with cookie banners or other content present to them.&lt;/p&gt;
&lt;p&gt;In short, while lab-based tools can give an indication of potential performance problems and help you debug and iterate, they may not represent how many of your visitors actually experience your website. Use field data for measuring real-world performance, and lab-based tools like Lighthouse for diagnostics of how to improve it. See also the &lt;a href=&quot;https://web.dev/vitals-tools/#when-to-use-lighthouse&quot;&gt;When to use Lighthouse&lt;/a&gt; section.&lt;/p&gt;
&lt;p&gt;Google measures Core Web Vitals through 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;. This is a public dataset collected from real Chrome users. It is the backbone of many Google and third-party tools which report a site&#39;s Core Web Vitals.&lt;/p&gt;
&lt;p&gt;CrUX has its limitations, though. It can often tell you &lt;em&gt;when&lt;/em&gt; there is a problem, but often has insufficient data to tell you &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;collect-your-own-field-data-if-possible&quot;&gt;Collect your own field data if possible &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#collect-your-own-field-data-if-possible&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best dataset for improving website performance in the field is the one &lt;em&gt;you&lt;/em&gt; build. That starts with collecting field data from your website&#39;s visitors. How you do this depends on the size of your organization, and whether you want to pay for &lt;a href=&quot;https://en.wikipedia.org/wiki/Real_user_monitoring#RUM_software&quot; rel=&quot;noopener&quot;&gt;a third-party solution&lt;/a&gt; or create your own.&lt;/p&gt;
&lt;p&gt;Paid solutions will almost certainly measure Core Web Vitals (and other performance metrics) and usually provide a variety of tools to dig into the resulting data. In large organizations with significant resources, this may be the preferred method.&lt;/p&gt;
&lt;p&gt;However, you may not be part of a large organization—or even one with the means to afford a third-party solution. In these cases, Google&#39;s &lt;a href=&quot;https://github.com/GoogleChrome/web-vitals&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;web-vitals&lt;/code&gt; library&lt;/a&gt; will help you gather &lt;em&gt;all&lt;/em&gt; Web Vitals. However, you&#39;ll be responsible for how that data is reported, stored, and analyzed.&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&#39;re building your own metrics collection and reporting system, &lt;a href=&quot;https://web.dev/vitals-field-measurement-best-practices/&quot;&gt;this guide of best practices&lt;/a&gt; is worth a read to avoid common pitfalls. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;If you&#39;re already using Google Analytics, but you haven&#39;t started collecting your own field data, there may be an opportunity for you to use the &lt;code&gt;web-vitals&lt;/code&gt; library to &lt;a href=&quot;https://web.dev/debug-performance-in-the-field/#usage-with-the-web-vitals-javascript-library&quot;&gt;send Web Vitals collected in the field to Google Analytics&lt;/a&gt; and use the &lt;a href=&quot;https://web.dev/vitals-ga4/&quot;&gt;BigQuery exports of GA4&lt;/a&gt; to report on the data.&lt;/p&gt;
&lt;h2 id=&quot;understanding-googles-tools&quot;&gt;Understanding Google&#39;s tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#understanding-googles-tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Regardless of whether you&#39;re collecting your own field data, there are several Google tools that may be useful in analyzing Core Web Vitals. Before establishing a workflow, a high-level overview of each tool can help you to understand which tools may—or may not—be best for you.&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; As you continue, understand that it&#39;s not necessary for you to use &lt;em&gt;all&lt;/em&gt; of the tools in this guide—only those that you believe will help you in improving your website&#39;s Core Web Vitals. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;chrome-user-experience-report-crux&quot;&gt;Chrome User Experience Report (CrUX) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#chrome-user-experience-report-crux&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned previously, CrUX is a public data set of field data gathered from &lt;a href=&quot;https://developer.chrome.com/docs/crux/methodology/#user-eligibility&quot; rel=&quot;noopener&quot;&gt;a segment of real Google Chrome users&lt;/a&gt; from millions of websites. It includes Core Web Vital metrics and other metrics for websites with sufficient traffic.&lt;/p&gt;
&lt;p&gt;CrUX is available as a monthly &lt;a href=&quot;https://developer.chrome.com/docs/crux/bigquery/&quot; rel=&quot;noopener&quot;&gt;BigQuery dataset&lt;/a&gt; at the origin level, or as a &lt;a href=&quot;https://developer.chrome.com/docs/crux/api/&quot; rel=&quot;noopener&quot;&gt;daily API&lt;/a&gt; at the URL or origin-level, provided a URL or origin has enough samples in the CrUX dataset. The BigQuery data is also viewable in an easy to use &lt;a href=&quot;https://developer.chrome.com/docs/crux/dashboard/&quot; rel=&quot;noopener&quot;&gt;CrUX Dashboard&lt;/a&gt; allowing sites to review historical trends for their site.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-crux&quot;&gt;When to use CrUX &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-crux&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Even if you gather your own field data, CrUX is still useful. Though CrUX represents a subset of Chrome users, it&#39;s helpful to compare your website&#39;s field data to see how it aligns with its CrUX data. There are advantages and disadvantages to each, which &lt;a href=&quot;https://web.dev/crux-and-rum-differences/&quot;&gt;can result in differences&lt;/a&gt;. If you currently don&#39;t gather &lt;em&gt;any&lt;/em&gt; field data for your website, CrUX is especially valuable to provide a high-level overview—provided your website is represented in its dataset.&lt;/p&gt;
&lt;p&gt;You can use CrUX directly, or via another tool (including those mentioned below). Using the CrUX dataset directly, either via BigQuery or the API, is useful to surface data that is not currently shown in other tools—for example country-level data is often not available on other tools, or to view the &lt;a href=&quot;https://developer.chrome.com/docs/crux/methodology/#metrics&quot; rel=&quot;noopener&quot;&gt;additional metrics in CrUX&lt;/a&gt; which again are often not surfaced in other tooling.&lt;/p&gt;
&lt;h4 id=&quot;when-not-to-use-crux&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use CrUX &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-crux&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;CrUX only represents Chrome users, and even then, &lt;a href=&quot;https://developer.chrome.com/docs/crux/methodology/#user-eligibility&quot; rel=&quot;noopener&quot;&gt;only a subset of Chrome users&lt;/a&gt;. A full RUM solution can include more experiences across Chrome and other browsers where they support the Web Vital metrics.&lt;/p&gt;
&lt;p&gt;Websites that don&#39;t receive enough traffic are not represented in the CrUX dataset. If this is the case for you, you&#39;ll need to gather your own field data to understand how your website performs in the field, as CrUX won&#39;t be an option. Alternatively, you will need to depend on lab data, but with the limitations that it may not be representative above.&lt;/p&gt;
&lt;p&gt;Since the data CrUX provides is a rolling average over the previous 28 days, it&#39;s not an ideal tool during development, as it will take a fair amount of time for improvements to be reflected in the CrUX dataset.&lt;/p&gt;
&lt;p&gt;Finally, as a public dataset, CrUX is limited to how much information it can make available, and how this data can be queried. Capturing your own RUM data allows you to gather more details (for example, &lt;a href=&quot;https://web.dev/debug-performance-in-the-field/#lcp&quot;&gt;the LCP element&lt;/a&gt;), and slice and dice the data more to identify problems. Do logged in users experience better or worse Core Web Vitals than logged out users? Do users with a slow LCP have a particular LCP element? Which interactions are causing high FID and INP values?&lt;/p&gt;
&lt;h3 id=&quot;pagespeed-insights-psi&quot;&gt;PageSpeed Insights (PSI) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#pagespeed-insights-psi&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PSI&lt;/a&gt; is a tool that reports field data from CrUX &lt;em&gt;and&lt;/em&gt; lab from Lighthouse for a given page. See those individual sections for more details.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-psi&quot;&gt;When to use PSI &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-psi&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;PSI is great for assessing CrUX performance at the page level or origin-level, for both mobile and desktop users. It&#39;s a good choice for an initial overview of Core Web Vitals for a page or site. It also allows you to easily view Core Web Vitals data for other sites like competitors.&lt;/p&gt;
&lt;p&gt;PSI also provides Lighthouse data, which gives useful recommendations to improve your Core Web Vitals—if the metrics align. Where these do not align, Lighthouse recommendations may be less relevant.&lt;/p&gt;
&lt;p&gt;Since Lighthouse is run from the server, it can form a more consistent baseline than running Lighthouse from DevTools.&lt;/p&gt;
&lt;h4 id=&quot;when-not-to-use-psi&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use PSI &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-psi&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;PSI is only available for public URLs. It cannot be used on development sites that are not publicly accessible.&lt;/p&gt;
&lt;p&gt;CrUX data is only available when sites meet certain &lt;a href=&quot;https://developer.chrome.com/docs/crux/methodology/#eligibility&quot; rel=&quot;noopener&quot;&gt;eligibility criteria&lt;/a&gt;, including site popularity thresholds. PSI is less useful when CrUX data is not available for a page or origin as it can only show the Lighthouse lab data in these cases.&lt;/p&gt;
&lt;p&gt;Similarly, if you only have origin-level CrUX data rather than the specific URL being tested, then this also limits its usefulness of correlating the origin-level field data to the page-level lab diagnostics. Having the origin-level field data is still very useful information to have as a summary of the site&#39;s performance and the Lighthouse audits may help, but extra caution should be used in this case.&lt;/p&gt;
&lt;p&gt;Finally, where page-level data is available in CrUX, but differs from the Lighthouse lab data, recommendations from Lighthouse may be of limited value. This can happen particularly for &lt;a href=&quot;https://web.dev/optimize-cls/#identifying-post-load-cls-issues&quot;&gt;post-load CLS issues&lt;/a&gt;, and for interactivity Core Web Vitals (FID and INP) where lab-based audits are less useful.&lt;/p&gt;
&lt;h3 id=&quot;search-console&quot;&gt;Search Console &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#search-console&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://search.google.com/search-console/about&quot; rel=&quot;noopener&quot;&gt;Search Console&lt;/a&gt; measures your site&#39;s search traffic and performance, &lt;a href=&quot;https://support.google.com/webmasters/answer/9205520&quot; rel=&quot;noopener&quot;&gt;including Core Web Vitals&lt;/a&gt;. It is only available to site owners who have &lt;a href=&quot;https://support.google.com/webmasters/answer/34592&quot; rel=&quot;noopener&quot;&gt;confirmed their ownership of the site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A valuable feature of Search Console is that it groups similar pages (for example, pages that use the same template) into a single group assessment. Search Console also includes a Core Web Vitals report based on field data from CrUX.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-search-console&quot;&gt;When to use Search Console &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-search-console&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Search Console is well-suited for both developers and those in non-developer roles to assess both search and page performance in ways other Google tools don&#39;t. Its presentation of CrUX data and grouping of pages by similarity offers novel insight into how performance improvements impact entire categories of pages.&lt;/p&gt;
&lt;h4 id=&quot;when-not-to-use-search-console&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use Search Console &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-search-console&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Search Console may not be a fit for projects that use different third-party tools which group pages by similarity, or if a website isn&#39;t represented in the CrUX dataset.&lt;/p&gt;
&lt;p&gt;Page grouping can also be somewhat confusing when the example pages in a group have different characteristics than the rest of the group—for example, if the group fails particular Core Web Vitals overall, but the example pages all seem to pass the same Core Web Vitals. This can happen when a group contains a long tail or seldomly visited pages that may be slower to load, as they&#39;re less likely to be cached. When there are sufficient volumes of these pages in the long tail, they can influence the group&#39;s overall pass rate.&lt;/p&gt;
&lt;h3 id=&quot;lighthouse&quot;&gt;Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; is a lab tool that provides specific opportunities for improving page performance. &lt;a href=&quot;https://web.dev/lighthouse-user-flows/&quot;&gt;Lighthouse user flows&lt;/a&gt; also allow developers to script interaction flows for performance testing beyond page load.&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; Because Lighthouse is a lab tool, and &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; are field metrics, it reports &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time&lt;/a&gt; instead. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; rel=&quot;noopener&quot;&gt;Lighthouse-CI&lt;/a&gt; is a related tool that runs Lighthouse during project builds and deploys to assist with performance regression testing. It presents a Lighthouse report along with pull requests, and tracks performance metrics over time.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-lighthouse&quot;&gt;When to use Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Lighthouse is excellent for finding performance improvement opportunities during development in both local and staging environments. Lighthouse CI is similarly useful in the build and deploy phases to staging and production environments, where performance regression testing is needed to preserve good user experiences.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Don&#39;t rely solely on Lighthouse CI during production deployments, as you may miss performance regressions that you&#39;d otherwise catch in local and staging environments during development with Lighthouse. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;when-not-to-use-lighthouse&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Lighthouse (or Lighthouse CI) &lt;strong&gt;is &lt;em&gt;not&lt;/em&gt; a substitute for field data&lt;/strong&gt;. Lighthouse is primarily a diagnostic tool listing potential issues and best practices from a predefined page load. The recommendations it surfaces may not always match the performance experienced by your users.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;strong&gt;Always concentrate on field Core Web Vitals over Lighthouse metrics and scores&lt;/strong&gt;. In particular, the Performance Score of Lighthouse is a broad measure of that lab test and &lt;a href=&quot;https://philipwalton.com/articles/my-challenge-to-the-web-performance-community/&quot;&gt;often does not correlate&lt;/a&gt; with field Core Web Vitals. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;While Lighthouse can be used to diagnose production sites through tools like PageSpeed Insights, Lighthouse would ideally be used in development and continuous integration environments to address performance issues before they reach production.&lt;/p&gt;
&lt;h3 id=&quot;web-vitals-extension&quot;&gt;Web Vitals extension &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#web-vitals-extension&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot; rel=&quot;noopener&quot;&gt;Web Vitals Chrome extension&lt;/a&gt; is a diagnostic tool that surfaces Core Web Vitals metrics as you browse the web. It also includes CrUX data for the current page if it is represented in the CrUX dataset, and provides &lt;a href=&quot;https://web.dev/debug-cwvs-with-web-vitals-extension/&quot;&gt;debugging information&lt;/a&gt; to help you identify Core Web Vitals performance problems.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-the-web-vitals-extension&quot;&gt;When to use the Web Vitals extension &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-the-web-vitals-extension&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Web Vitals extension can be used by anyone in any role to assess a page&#39;s Core Web Vitals at all points of the page lifecycle. It is useful as a &amp;quot;live&amp;quot; view of performance as you interact with the page to attempt to uncover performance issues—particularly for post-load issues you might see with the CLS and INP metrics.&lt;/p&gt;
&lt;h4 id=&quot;when-not-to-use-the-web-vitals-extension&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use the Web Vitals extension &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-the-web-vitals-extension&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Web Vitals extension isn&#39;t a holistic assessment of page performance. In addition, the metrics it reports are highly dependent the environment in which it runs, and developers often have higher powered machines or access to faster networks.&lt;/p&gt;
&lt;h3 id=&quot;the-performance-panel-in-chrome-devtools&quot;&gt;The Performance panel in Chrome DevTools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#the-performance-panel-in-chrome-devtools&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt; is a collection of in-browser development tools, including the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/#performance&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt;. The Performance panel is a lab tool that profiles all page activity during page load or a recorded time period. It offers deep insight into everything it observes across dimensions such as network, rendering, painting, and scripting activity, as well as a page&#39;s Core Web Vitals.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-the-performance-panel&quot;&gt;When to use the Performance panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-to-use-the-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Performance panel should be used by developers during development to gain deep insight into page performance. This is particularly useful to debug responsiveness issues affecting FID or INP. Once a poorly responding interaction is identified and repeatable, the Performance panel can provide a wealth of data as to what is going on in the browser to help understand the issue, from main thread blocking, to JavaScript call stacks, to rendering work.&lt;/p&gt;
&lt;h4 id=&quot;when-not-to-use-the-performance-panel&quot;&gt;When &lt;em&gt;not&lt;/em&gt; to use the Performance panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#when-not-to-use-the-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Performance panel is a developer tool that provides lab data only. It&#39;s not a substitute for field data. It contains a lot of debugging information, but because of that, it may not be easy to use for novice developers or those in non-developer roles.&lt;/p&gt;
&lt;h2 id=&quot;a-three-step-workflow-for-ensuring-your-websites-core-web-vitals-stay-healthy&quot;&gt;A three step workflow for ensuring your website&#39;s Core Web Vitals stay healthy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#a-three-step-workflow-for-ensuring-your-websites-core-web-vitals-stay-healthy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When working to improve the user experience, it&#39;s best to think of the process as a continuous cycle. For improving Core Web Vitals and other performance metrics, one approach could be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Evaluate website health and identify pain points.&lt;/li&gt;
&lt;li&gt;Debug and optimize.&lt;/li&gt;
&lt;li&gt;Monitor with continuous integration tools to catch and prevent regressions.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A diagram of a three step process, rendered as a continuous cycle. The first step reads &amp;#x27;Evaluate website health and identify paint points&amp;#x27;, the second &amp;#x27;Debug and optimize&amp;#x27;, and the third &amp;#x27;Monitor and continuous development&amp;#x27;.&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/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/9k3o679FUq63WT1kbxHe.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;step-1-evaluate-website-health-and-identify-opportunities-for-improvement&quot;&gt;Step 1: Evaluate website health and identify opportunities for improvement &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#step-1-evaluate-website-health-and-identify-opportunities-for-improvement&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is best to start with field data to evaluate website health.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; to view overall Core Web Vitals experience metrics on the origin, and specific information on an individual URL.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://search.google.com/search-console/about&quot; rel=&quot;noopener&quot;&gt;Search Console&lt;/a&gt; can be useful to identify pages which need improvement where its page grouping feature works well for your site.&lt;/li&gt;
&lt;li&gt;If you have RUM data, then that is often the best option to be able to identify particular pages or traffic segments with issues.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Whether you analyze field data you collect yourself or CrUX data, this first step is vital. If you&#39;re not gathering field data, CrUX data may be enough to guide you—again, provided your website is represented in the dataset.&lt;/p&gt;
&lt;h4 id=&quot;analyze-site-performance-with-pagespeed-insights&quot;&gt;Analyze site performance with PageSpeed Insights &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#analyze-site-performance-with-pagespeed-insights&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of how PageSpeed Insights portrays CrUX data for a URL&amp;#x27;s Core Web Vitals. Each of the Core Web Vitals is displayed separately, while grouping each Core Web Vital in the &amp;#x27;Good&amp;#x27;, &amp;#x27;Needs Improvement&amp;#x27;, and &amp;#x27;Poor&amp;#x27; thresholds for the last 28 days.&quot; decoding=&quot;async&quot; height=&quot;477&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/YEe3RQwgIWgQTHFV5sc0.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;PageSpeed Insights displays the CrUX data covering the last 28 days of user experience data at the 75th percentile. This means that if 75% of user experiences meet the &lt;a href=&quot;https://web.dev/defining-core-web-vitals-thresholds/&quot;&gt;threshold set for a given metric&lt;/a&gt;, then the experience is considered &amp;quot;good&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you have a specific page in mind to look at the performance of, then use that. For an overall view of a site when you first start optimizing, you may wish to start with the home page, as it is typically one of the most popular pages on many sites.&lt;/p&gt;
&lt;p&gt;Concentrate on the &lt;strong&gt;what your real users are experiencing&lt;/strong&gt; section of PSI initially. You will see up to four views of the data: mobile and desktop for the URL entered and the whole origin. Compare these and see how they differ. Mobile is typically less performant than desktop since it is a more resource-constrained device operating under potentially less stable network conditions. If the URL and origin data are significantly different, then try to understand why: home pages are often the first pages visited (that is, a landing page) so can be slower than the origin users take the full brunt of an unprimed browser cache. Subsequent pages will likely load faster, as any shared assets will be cached, bringing down the aggregate origin-level data.&lt;/p&gt;
&lt;p&gt;PSI also shows all three Core Web Vitals (LCP, CLS, and FID) and the pending INP metric, plus the diagnostic TTFB and FCP metrics. Are any of the Core Web Vitals failing, and by how much? This will indicate where to concentrate your efforts.&lt;/p&gt;
&lt;p&gt;Understand the relationships between these numbers—particularly for LCP. If LCP is slow, as it is in this example, then look at TTFB and FCP which are both milestones to that metric. In this example we have a 1.8 second TTFB, which is going to make it very tough to meet the 2.5 second recommended threshold for good LCP. This suggests either a slow backend (server issues or a lack of CDN), slower networks, or redirects delaying the first HTML bytes. Look at the &lt;a href=&quot;https://web.dev/optimize-ttfb/&quot;&gt;Optimize TTFB guide&lt;/a&gt; for more information. FCP takes another second on top of that, which again may be indicative of slower networks. LCP is not long after FCP in this example suggesting the LCP resource is well optimized once the page itself loads.&lt;/p&gt;
&lt;p&gt;For CLS, look at the CrUX CLS and the Lighthouse CLS scores to see if this is a load CLS issue (which Lighthouse will catch and advise on), or a post-load CLS issue that Lighthouse won&#39;t catch. More for information &lt;a href=&quot;https://web.dev/optimize-cls/#understanding-where-your-shifts-are-coming-from&quot;&gt;see the Optimize CLS guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For responsiveness, look at the FID and INP scores. Look at the TBT audits in Lighthouse to see if a lot of JavaScript processing is happening during the initial page load, which is likely to impact INP. INP can be a tricky metric to improve, so consult the &lt;a href=&quot;https://web.dev/optimize-inp/&quot;&gt;Optimize INP guide&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h4 id=&quot;identify-poorly-performing-pages-in-search-console&quot;&gt;Identify poorly performing pages in Search Console &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#identify-poorly-performing-pages-in-search-console&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of a Core Web Vitals report in Search Console. The report is broken down into Desktop and Mobile categories, with line graphs detailing the distribution of pages with Core Web Vitals in the &amp;#x27;Good&amp;#x27;, &amp;#x27;Needs Improvement&amp;#x27;, and &amp;#x27;Poor&amp;#x27; categories over time.&quot; decoding=&quot;async&quot; height=&quot;639&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/DWdv878oyTdEWQViRh06.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;While PSI is useful when you have a specific URL you want to test or the site as a whole, Search Console can help target your efforts to particular types of pages. This is particularly useful if many pages share common themes or technologies and Search Console can successfully identify these.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://support.google.com/webmasters/answer/9205520&quot; rel=&quot;noopener&quot;&gt;Core Web Vitals report in Search Console&lt;/a&gt; shows the big picture of your website&#39;s performance, but you can still drill down into specific pages that need attention. With Search Console, you can also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify individual page groups that need improvement, and those that currently provide a good user experience.&lt;/li&gt;
&lt;li&gt;Get granular data on performance by URL grouped by status, metric, and groups of similar web pages (such as product detail pages on an e-commerce website).&lt;/li&gt;
&lt;li&gt;Get detailed reports that bucket URLs in each user experience quality category for both mobile and desktop.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The data in Search Console is different from what&#39;s shown in the PageSpeed Insights origin view or the CrUX dashboard. This is because Search Console organizes information by URL, whereas PageSpeed Insights origin view and CrUX Dashboard organizes data by origin. If you have few poorly performing URLs, but those URLs receive a large portion of overall traffic, Search Console will only show a few poorly performing URLs while CrUX dashboard will show a high percentage of poor user experiences. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Once you have some specific pages to look at, you can use PSI as explained previously to gather further understanding of the issues for those pages.&lt;/p&gt;
&lt;h3 id=&quot;step-2-debug-and-optimize&quot;&gt;Step 2: Debug and optimize &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#step-2-debug-and-optimize&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In step 1, you should have identified pages which require performance improvements, and also which of the Core Web Vitals metrics you want to improve. You can use the Google tooling to get further information to understand the root cause to identify the issue.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run a &lt;a href=&quot;https://web.dev/vitals-tools/#Lighthouse&quot;&gt;Lighthouse&lt;/a&gt; audit to get page-level guidance&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://web.dev/vitals-tools/#web-vitals-extension&quot;&gt;Web Vitals extension&lt;/a&gt; to analyze Core Web Vitals in real time.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://web.dev/vitals-tools/#the-performance-panel-in-chrome-devtools&quot;&gt;Performance panel&lt;/a&gt; in Chrome DevTools to debug performance issues and test code changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more detailed guidance, see these guides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-lcp/&quot;&gt;Optimizing LCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-cls/&quot;&gt;Optimizing CLS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/&quot;&gt;Optimizing FID&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-inp/&quot;&gt;Optimizing INP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;uncover-opportunities-with-lighthouse&quot;&gt;Uncover opportunities with Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#uncover-opportunities-with-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;PageSpeed Insights runs Lighthouse for you, but for local development it is also possible to run Lighthouse from Chrome DevTools, which is useful to validate fixes locally.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of a Lighthouse report within Chrome DevTools. The report breaks down scores across five categories, with the report focused on the &amp;#x27;Performance&amp;#x27; category, with results at the bottom of the report window.&quot; decoding=&quot;async&quot; height=&quot;526&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/k6HffrY6tUbreyzi2mVk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;A key point is to validate that the Lighthouse audit replicates the issues you are trying to solve (for example, slow LCP, or CLS issues). Out of the box, Lighthouse only assesses the user experience during page load. Since it&#39;s a lab tool, it also excludes FID and INP in favor of TBT.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; By default, Lighthouse simulates a mid-tier mobile device on a throttled slow 4G connection. This may find issues that wouldn&#39;t ordinarily appear on high-speed devices and fast internet connections. This simulated throttling may not be representative of the variety of user experiences among your website&#39;s user base at the 75th percentile. However, these metrics are an indicator of where performance problems exist, and may translate into better performance overall in the field if the problems Lighthouse finds are addressed. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;When the Lighthouse metrics suggest a similar problem as the one you are trying to solve, the wealth of information in its audits can help identify issues and suggest solutions.&lt;/p&gt;
&lt;p&gt;You can filter the audits to just the Core Web Vitals you are interested in to focus on fixes for issues related to a specific metric:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse filter options for key metrics&quot; decoding=&quot;async&quot; height=&quot;100&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 700px) 700px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/wae09J8FYUe0PvFBkH4b.png?auto=format&amp;w=1400 1400w&quot; width=&quot;700&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;For FID and INP, use the TBT audits to identify issues that can potentially affect those metrics, but be aware that without interactions, Lighthouse is limited in how much it can diagnose.&lt;/p&gt;
&lt;h4 id=&quot;analyze-in-real-time-with-the-web-vitals-extension&quot;&gt;Analyze in real time with the Web Vitals extension &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#analyze-in-real-time-with-the-web-vitals-extension&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Web Vitals Chrome extension shows Core Web Vitals in real time during page load &lt;em&gt;and&lt;/em&gt; while browsing a page. Because of this, it can capture FID and INP as well as layout shifts that occur after load. The debugging options show more detailed information on each metric:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Web Vitals Extension console logging showing INP target, event type, and breakdown&quot; decoding=&quot;async&quot; height=&quot;448&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/kxh8TRS2585OJTZJmWmt.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;It&#39;s best to think of the Web Vitals extension as a spot-checking tool to find performance issues, not a comprehensive debugging tool—that&#39;s a job for the Performance panel in Chrome DevTools.&lt;/p&gt;
&lt;h4 id=&quot;drill-down-with-the-performance-panel&quot;&gt;Drill down with the Performance panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#drill-down-with-the-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Performance panel in Chrome DevTools profiles all page behavior during a recorded period of time.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;466&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/JmVcoLckgeukluuJONDe.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Key timings—such as LCP, for example—are shown in the Timings track. Click on these for more details.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Layout Shifts&lt;/strong&gt; track highlights layout shifts and clicking on these provides more details about the elements that shifted for debugging CLS.&lt;/p&gt;
&lt;p&gt;Long Tasks (that can lead to FID and INP issues) are also highlighted with red triangles.&lt;/p&gt;
&lt;p&gt;These features—as well as information in other parts of the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/#performance&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt;—can help you determine whether fixes are having any effect on a page&#39;s Core Web Vitals.&lt;/p&gt;
&lt;h4 id=&quot;debug-core-web-vitals-in-the-field&quot;&gt;Debug Core Web Vitals in the field &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#debug-core-web-vitals-in-the-field&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Lab tools can&#39;t always identify the cause of all Core Web Vitals issues affecting your users. This is one reason why it&#39;s so important to collect your own field data, as it takes factors into account that lab data cannot.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://web.dev/debug-performance-in-the-field/&quot;&gt;debug performance in the field&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&quot;step-3-monitor-for-changes&quot;&gt;Step 3: Monitor for changes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#step-3-monitor-for-changes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A collection of icons for Google tools. From left to right, the icons represent &amp;#x27;CrUX on BigQuery&amp;#x27;, &amp;#x27;CrUX API&amp;#x27;, &amp;#x27;PSI API&amp;#x27;, &amp;#x27;web-vitals.js&amp;#x27;, with &amp;#x27;Lighthouse CI&amp;#x27; at the far right.&quot; decoding=&quot;async&quot; height=&quot;185&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/LqEnonUKd8j3QGK3Ax7w.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Once you have fixed any issues, you want to ensure they have the desired effect and that new issues do not disrupt your Core Web Vitals. This requires monitoring for performance issues as part of developer workflow to prevent performance issues being released to production, and monitoring the field data regularly to ensure this is the case.&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://youtu.be/YJGCZCaIZkQ?t=112&quot;&gt;Research by Google&lt;/a&gt; has shown that most performance improvements tend to regress within six months. A website needs continuous monitoring in both the lab &lt;em&gt;and&lt;/em&gt; the field to identify worsening trends in Core Web Vitals and other performance metrics to avoid regressions. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;monitor-for-performance-requisitions-in-continuous-integration-ci-environments&quot;&gt;Monitor for performance requisitions in Continuous Integration (CI) environments &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#monitor-for-performance-requisitions-in-continuous-integration-ci-environments&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; rel=&quot;noopener&quot;&gt;Lighthouse-CI&lt;/a&gt; allows you to automatically run Lighthouse audits on code commits to prevent performance regressions entering code. This can check performance timings (which &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/variability&quot; rel=&quot;noopener&quot;&gt;are subject to variability&lt;/a&gt;), or for just &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/&quot; rel=&quot;noopener&quot;&gt;the performance audits&lt;/a&gt;, as a linting tool to prevent bad practices in the code.&lt;/p&gt;
&lt;h4 id=&quot;view-website-health-trends-with-field-data&quot;&gt;View website health trends with field data &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#view-website-health-trends-with-field-data&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;While you should aim to catch and fix all performance issues before they make it to production, monitoring your field data via RUM is essential to find any that slip through. There are many commercial RUM products available that can help with this. The &lt;a href=&quot;https://github.com/GoogleChrome/web-vitals&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;web-vitals&lt;/code&gt;&lt;/a&gt; JavaScript library can automate a website&#39;s field data collection, and optionally use this data to power custom dashboards and alerting systems.&lt;/p&gt;
&lt;p&gt;For sites without a RUM solution, you can &lt;a href=&quot;https://developer.chrome.com/docs/crux/dashboard/&quot; rel=&quot;noopener&quot;&gt;use the CrUX Dashboard&lt;/a&gt; as a basic trend analysis of field data. It reports the following for sites in CrUX:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Site overview&lt;/strong&gt;, which segments Core Web Vitals into desktop and mobile device types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Historical trend by metric type&lt;/strong&gt;, which is a distribution of metrics over time for each available monthly release of CrUX report data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User demographics&lt;/strong&gt;, which illustrates the distribution of page views across an entire origin for users in each demographic including device and &lt;a href=&quot;https://developer.mozilla.org/docs/Glossary/Effective_connection_type&quot; rel=&quot;noopener&quot;&gt;effective connection&lt;/a&gt; types.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of the CrUX dashboard. The dashboard breaks down LCP, FID, and CLS into desktop and mobile categories, with each category showing the distribution of values that lie within &amp;#x27;Good&amp;#x27;, &amp;#x27;Needs Improvement&amp;#x27; and &amp;#x27;Poor&amp;#x27; thresholds for the previous month.&quot; decoding=&quot;async&quot; height=&quot;837&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/jL3OLOhcWUQDnR4XjewLBx4e3PC3/oF2PQELFtdICPN10aZge.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The CrUX Dashboard is based on the &lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-bigquery/&quot; rel=&quot;noopener&quot;&gt;CrUX BigQuery dataset&lt;/a&gt;, which is updated once a month. This can be a good reminder to regularly check in on your Core Web Vitals.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Even if your website is represented in CrUX, you should still collect your own field data, since CrUX doesn&#39;t include &lt;em&gt;all&lt;/em&gt; users of Chrome or even other browsers—but it&#39;s certainly a good place to start in the absence of any field data. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ensuring fast and delightful user experiences requires a performance-first mindset and adoption of a workflow to ensure progress. With the right tools and processes to audit, debug, and monitor, building great user experiences and staying within the thresholds defined for good Core Web Vitals is within your reach.&lt;/p&gt;
</content>
    <author>
      <name>Barry Pollard</name>
    </author><author>
      <name>Antoine Bisch</name>
    </author><author>
      <name>Garima Mimani</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Elizabeth Sweeny</name>
    </author>
  </entry>
  
  <entry>
    <title>Evolving Cumulative Layout Shift in web tooling</title>
    <link href="https://web.dev/cls-web-tooling/"/>
    <updated>2021-06-02T00:00:00Z</updated>
    <id>https://web.dev/cls-web-tooling/</id>
    <content type="html" mode="escaped">&lt;p&gt;Today we would like to share how we are evolving measurement of the
&lt;a href=&quot;https://web.dev/cls&quot;&gt;Cumulative Layout Shift&lt;/a&gt; (CLS)
metric across a number of Chrome&#39;s web tooling surfaces.
For developers, these changes will better reflect the user-experience for
&lt;a href=&quot;https://web.dev/evolving-cls/&quot;&gt;long-lived pages&lt;/a&gt;
(such as those with infinite scroll or single-page apps).
These updates to CLS will be rolling out to tools including Lighthouse,
PageSpeed Insights, and Chrome UX Report.&lt;/p&gt;
&lt;p&gt;We all wish we saw fewer layout shifts on the web.
This is where the CLS metric has proved useful in measuring the visual stability of a web page.
It helps to encourage sites to better set dimensions for content,
such as images or ads,
that may contribute to surprising jumps of content for their users.&lt;/p&gt;
&lt;p&gt;The metric is named &amp;quot;cumulative&amp;quot;
because the score of each individual shift is summed throughout the lifespan of a page.
While all layout shifts on the web cause poor user experiences,
long-lived pages like Single-Page Apps (SPAs) or infinite scroll apps naturally accumulate more CLS over time.
By capping the aggregation to the worst &#39;window&#39; of shifts,
CLS can now be more consistently measured regardless of session duration.&lt;/p&gt;
&lt;p&gt;As we announced in &lt;a href=&quot;https://web.dev/evolving-cls/&quot;&gt;Evolving the CLS metric&lt;/a&gt;, we are adjusting the CLS metric to a
&lt;a href=&quot;https://web.dev/evolving-cls/&quot;&gt;maximum session window with a 1 second gap, capped at 5 seconds&lt;/a&gt;,
this update better reflects the user experience for long lived pages.
With this change in place,
70% of origins should not expect to see any CLS change at the 75th percentile,
and the remaining 30% of origins will see an improvement.&lt;/p&gt;
&lt;h2 id=&quot;rolling-out-the-windowing-adjustment-to-cls&quot;&gt;Rolling out the windowing adjustment to CLS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#rolling-out-the-windowing-adjustment-to-cls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve talked about the updated CLS definition being a max session window with a 1 second gap,
capped at 5 seconds. What does that mean for tools?&lt;/p&gt;
&lt;p&gt;Starting today,
this change to CLS has been rolled out across a number of Chrome&#39;s web tooling surfaces including
Lighthouse, PageSpeed Insights, and Chrome UX Report.
Below you can see a summary of the CLS windowing adjustment rollout,
as well as which tools still provide the ability to benchmark against the original implementation.&lt;/p&gt;
&lt;div&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Tool&lt;/th&gt;
        &lt;th&gt;CLS windowing adjustment  &#39;live&#39;&lt;/th&gt;
        &lt;th&gt;&quot;Old&quot; CLS Availability&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Lighthouse DevTools Panel&lt;/td&gt;
        &lt;td&gt;Canary channel, 2 June 2021&lt;/td&gt;
        &lt;td&gt;N/A&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse#cli&quot;&gt;
        Lighthouse CLI&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;v8, released 1 June 2021&lt;/td&gt;
        &lt;td&gt;Available as totalCumulativeLayoutShift in Lighthouse v8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot;&gt;Lighthouse CI&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;v0.7.3, 3 June 2021&lt;/td&gt;
        &lt;td&gt;N/A&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/&quot;&gt;
        PageSpeed Insights&lt;/a&gt; (PSI)&lt;/td&gt;
        &lt;td&gt;1 June 2021&lt;/td&gt;
        &lt;td&gt;NA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/get-started&quot;&gt;
        PSI API&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;1 June 2021&lt;/td&gt;
        &lt;td&gt;Available in the &lt;code&gt;lighthouseResult&lt;/code&gt; as &lt;code&gt;totalCumulativeLayoutShift&lt;/code&gt;. Not available in the field &lt;code&gt;loadingExperience&lt;/code&gt; data&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://web.dev/chrome-ux-report-bigquery/&quot;&gt;
        Chrome UX Report (CrUX) - BigQuery&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;202105 dataset, published 8 June 2021&lt;/td&gt;
        &lt;td&gt;Available as &lt;code&gt;experimental.uncapped_cumulative_layout_shift&lt;/code&gt; through 202111&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://developer.chrome.com/docs/crux/api/&quot;&gt;
        Chrome UX Report (CrUX) - API&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;1 June 2021&lt;/td&gt;
        &lt;td&gt;After 1 June 2021, available as
        &lt;code&gt;experimental_uncapped_cumulative_layout_shift&lt;/code&gt;
        December 14th, 2021&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
    &lt;/tr&gt;&lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Chrome DevTools will also be updated to support the windowing adjustment shortly. The update to CLS has also been made to &lt;a href=&quot;https://search.google.com/search-console/about&quot; rel=&quot;noopener&quot;&gt;Search Console&lt;/a&gt; and will be reflective from 1 June, 2021.&lt;/p&gt;
&lt;p&gt;For most developers,
this change is expected to happen seamlessly with no action needed to take advantage of data from the fix.&lt;/p&gt;
&lt;h2 id=&quot;old-cls&quot;&gt;&amp;quot;Old&amp;quot; CLS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#old-cls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a reminder, the &amp;quot;old&amp;quot; CLS measures layout shift over the entire lifespan of the page. As some developers may wish to monitor the older definition of CLS alongside the windowing-adjustment,
we have good news to share: we are exposing &amp;quot;old CLS&amp;quot; in Lighthouse and CrUX.&lt;/p&gt;
&lt;p&gt;In Lighthouse v8,
it&#39;s available in the JSON as
&lt;code&gt;audits[&#39;cumulative-layout-shift&#39;].details.items[0].totalCumulativeLayoutShift&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&#39;ll find it as
&lt;code&gt;experimental_uncapped_cumulative_layout_shift&lt;/code&gt;
in the CrUX API and as
&lt;code&gt;experimental.uncapped_cumulative_layout_shift&lt;/code&gt; in CrUX BigQuery.&lt;/p&gt;
&lt;p&gt;After June 1st, CrUX API requests will return the &amp;quot;old CLS&amp;quot; metric:&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;origin&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://web.dev&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;metrics&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;experimental_uncapped_cumulative_layout_shift&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After June 8, the following
&lt;a href=&quot;https://developer.chrome.com/docs/crux/bigquery/&quot; rel=&quot;noopener&quot;&gt;CrUX BigQuery&lt;/a&gt;
will compare old and new CLS:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt;&lt;br /&gt;  new_data &lt;span class=&quot;token keyword&quot;&gt;AS&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;SELECT&lt;/span&gt;&lt;br /&gt;    cls&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token identifier&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;`&lt;/span&gt;chrome-ux-report.all.202105&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;    UNNEST&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layout_instability&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cumulative_layout_shift&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;histogram&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; cls&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;    origin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://web.dev&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; effective_connection_type&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;4G&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; form_factor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;phone&#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;  old_data &lt;span class=&quot;token keyword&quot;&gt;AS&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;SELECT&lt;/span&gt;&lt;br /&gt;    uncapped_cls&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token identifier&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;`&lt;/span&gt;chrome-ux-report.all.202105&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;    UNNEST&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;experimental&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uncapped_cumulative_layout_shift&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;histogram&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; uncapped_cls&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;    origin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://web.dev&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; effective_connection_type&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;4G&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; form_factor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;phone&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;  cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token identifier&quot;&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;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token identifier&quot;&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;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;density &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; cls_density&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  uncapped_cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;density &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; uncapped_cls_density&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;  new_data&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt;&lt;br /&gt;  old_data&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt;&lt;br /&gt;  new_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; old_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uncapped_cls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You will be able to continue relying on this data to be present for a period of up to 6 months,
with &amp;quot;old CLS&amp;quot; being retired on December 14th, 2021.&lt;/p&gt;
&lt;h2 id=&quot;updating-the-cls-weighting-in-lighthouse&quot;&gt;Updating the CLS weighting in Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#updating-the-cls-weighting-in-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When CLS was first introduced in Lighthouse,
it was a brand new sparkly metric.
As such, in order to make sure developers had time to test, benchmark,
and optimize against it, CLS was weighed less heavily in the performance score.&lt;/p&gt;
&lt;p&gt;Now, after having had some time in the hands of developers,
the Lighthouse score has increased the weight of CLS from 5% to 15%,
consistent with the methodology of having Core Web Vitals
be the most heavily weighted metrics in the Lighthouse score.&lt;/p&gt;
&lt;p&gt;You can find the updated weightings of metrics in Lighthouse v8 in the
&lt;a href=&quot;https://googlechrome.github.io/lighthouse/scorecalc/&quot; rel=&quot;noopener&quot;&gt;scoring calculator&lt;/a&gt;.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse scoring calculator&quot; decoding=&quot;async&quot; height=&quot;405&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/UAslFmRMON2y5qtY1TZE.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Lighthouse 8.0&#39;s CLS implementation includes both windowing and CLS contribution from subframes. Prior to 8.0, CLS in Lighthouse didn&#39;t include subframes&#39; CLS in the metric calculation, but now does. And just for confirmation, field CLS measured by CrUX also handles windowing and subframes similarly.&lt;/p&gt;
&lt;p&gt;Still, the primary difference between lab and field CLS is that lab CLS&#39;s window of observation ends at &amp;quot;fully loaded&amp;quot; as determined under lab conditions, whereas in the field, the window of observation extends to the entire page lifetime, including post-load activity. That said, the windowing adjustment does mitigate this difference substantially.&lt;/p&gt;
&lt;h2 id=&quot;measuring-in-the-field-yourself&quot;&gt;Measuring in the field yourself &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#measuring-in-the-field-yourself&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Should you wish to measure the latest CLS implementation,
you can also record this for your field data via RUM using the &lt;a href=&quot;https://web.dev/cls/#measure-cls-in-javascript&quot;&gt;following&lt;/a&gt; PerformanceObserver snippet.&lt;/p&gt;
&lt;p&gt;Or by relying directly on the
&lt;a href=&quot;https://github.com/GoogleChrome/web-vitals&quot; rel=&quot;noopener&quot;&gt;Web Vitals JavaScript library&lt;/a&gt;,
which has also been updated with this change.&lt;/p&gt;
&lt;h2 id=&quot;additional-updates&quot;&gt;Additional updates &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#additional-updates&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Outside of the updates to Cumulative Layout Shift,
the following metrics-related updates have also been made to our web tooling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&#39;re updating to
&lt;a href=&quot;https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/speed/metrics_changelog/2020_11_lcp.md&quot; rel=&quot;noopener&quot;&gt;the most recent definition of the Largest Contentful Paint metric&lt;/a&gt;.
CrUX API, PSI, PSI API, Search Console will update on June 1, 2021. CrUX BigQuery will update on June 8, 2021.&lt;/li&gt;
&lt;li&gt;In CrUX, First Contentful Paint tri-binning thresholds have been updated to be,
Good: [0-1.8s], Needs Improvement: (1.8s-3s), Poor: [3s-∞]&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/cls-web-tooling/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We expect this change to reflect a smooth transition for most sites and encourage you to check out
&lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Web Vitals&lt;/a&gt; and
&lt;a href=&quot;https://web.dev/optimize-cls&quot;&gt;Optimize CLS&lt;/a&gt;
for tips and tricks on how to measure and optimize your layout shifts away.
As always, feel free to reach out on the
&lt;a href=&quot;https://groups.google.com/g/web-vitals-feedback&quot; rel=&quot;noopener&quot;&gt;web-vitals-feedback group&lt;/a&gt;
for feedback about the metrics and our tooling specific feedback forums for
&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;, and
&lt;a href=&quot;https://groups.google.com/a/chromium.org/g/chrome-ux-report&quot; rel=&quot;noopener&quot;&gt;Chrome UX Report&lt;/a&gt;
for tooling issues. Cheers!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Johannes Henkel, Rick Viscomi, Vivek Sekhar, Rachel Andrew, Milica Mihajlija, Jeff Jose and Paul Irish for their feedback.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hero image by Barn Images / @barnimages on &lt;a href=&quot;https://unsplash.com/photos/t5YUoHW6zRo&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Elizabeth Sweeny</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimizing Web Vitals using Lighthouse</title>
    <link href="https://web.dev/optimize-vitals-lighthouse/"/>
    <updated>2021-05-11T00:00:00Z</updated>
    <id>https://web.dev/optimize-vitals-lighthouse/</id>
    <content type="html" mode="escaped">&lt;p&gt;Today, we&#39;ll cover new tooling features in Lighthouse, PageSpeed and DevTools to help identify
how your site can improve on the &lt;a href=&quot;https://web.dev/vitals&quot;&gt;Web Vitals&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a refresher on the tools, &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; is an
open-source, automated tool for improving the quality of web pages. You can find it in the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome
DevTools&lt;/a&gt; suite of debugging tools and run
it against any web page, public or requiring authentication. You can also find Lighthouse in
&lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Fstore.google.com&quot; rel=&quot;noopener&quot;&gt;PageSpeed
Insights&lt;/a&gt;,
&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; rel=&quot;noopener&quot;&gt;CI&lt;/a&gt; and
&lt;a href=&quot;https://www.webpagetest.org/easy&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lighthouse 7.x includes new features like element screenshots, for easier visual inspection of
parts of your UI impacting user-experience metrics (e.g. what nodes are contributing to layout
shift).&lt;/p&gt;
&lt;figure&gt;
&lt;video muted=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot;&gt;
&lt;source type=&quot;video/mp4&quot; src=&quot;https://storage.googleapis.com/web-dev-uploads/video/1L2RBhCLSnXjCnSlevaDjy3vba73/3G0x4Z1dmOcsusG7j1LE.mp4&quot; width=&quot;1920&quot; height=&quot;1080&quot; /&gt;
&lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;We&#39;ve also shipped support for element screenshots on PageSpeed Insights, enabling a way to more
easily spot issues for one-off performance runs of pages.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Element Screenshots highlighting the DOM node contributing to layout shift in the page&quot; decoding=&quot;async&quot; height=&quot;483&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/mfkWFzyfO9XlJLYS80DE.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;measure-core-web-vitals&quot;&gt;Measure Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#measure-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse can
&lt;a href=&quot;https://web.dev/vitals-measurement-getting-started/#measuring-web-vitals-using-lab-data&quot;&gt;synthetically&lt;/a&gt; measure
the &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals metrics&lt;/a&gt; including &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt;, &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative
Layout Shift&lt;/a&gt; and &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time&lt;/a&gt; (a lab proxy for &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt;).
These metrics reflect loading, layout stability, and interaction readiness. Other metrics such as
&lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; highlighted in the &lt;a href=&quot;https://developer.chrome.com/devsummit/sessions/future-of-core-web-vitals/&quot; rel=&quot;noopener&quot;&gt;future of
Core Web Vitals (CWV)&lt;/a&gt; are there too.&lt;/p&gt;
&lt;p&gt;The &amp;quot;Metrics&amp;quot; section of the Lighthouse report includes lab versions of these metrics. You can use
this as a summary view of what aspects of user-experience require your attention.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse peformance metrics&quot; decoding=&quot;async&quot; height=&quot;485&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VkLhdNb3fxtfttFZ1S6E.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; Lighthouse focuses on measuring user-experience during the initial page load in a lab setting, emulating a slow phone or desktop machine. If there is behavior on your page that may cause layout shifts or long JavaScript tasks after page-load, the lab metrics will not reflect this. Try the DevTools Performance panel, &lt;a href=&quot;https://search.google.com/search-console/about&quot;&gt;Search Console&lt;/a&gt;, the &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma?hl=en&quot;&gt;Web Vitals extension&lt;/a&gt;, or &lt;a href=&quot;https://web.dev/vitals-measurement-getting-started/#measuring-web-vitals-using-rum-data&quot;&gt;RUM&lt;/a&gt; for a post-load view into the metrics. &lt;/div&gt;&lt;/aside&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Web Vitals lane in the devtools performance panel&quot; decoding=&quot;async&quot; height=&quot;476&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/PLMoiQpi12jT7BJUvlOJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;The new Web Vitals option in the DevTools Performance panel displays a
track which highlights metric moments, such as Layout Shift (LS) shown above.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/vitals-field-measurement-best-practices/&quot;&gt;Field metrics&lt;/a&gt;, such as those found in the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome UX
Report&lt;/a&gt; or
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Performance/Rum-vs-Synthetic&quot; rel=&quot;noopener&quot;&gt;RUM&lt;/a&gt;, do not have this
limitation and are a valuable complement to lab data as they reflect the experience real users
have. Field data can&#39;t offer the kinds of diagnostic information you get in the lab, so the two go
hand in hand.&lt;/p&gt;
&lt;h2 id=&quot;identify-where-you-can-improve-on-web-vitals&quot;&gt;Identify where you can improve on Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#identify-where-you-can-improve-on-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;identify-the-largest-contentful-paint-element&quot;&gt;Identify the Largest Contentful Paint element &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#identify-the-largest-contentful-paint-element&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;LCP is a measurement of perceived loading experience. It marks the point during page load when the
primary–or &amp;quot;largest&amp;quot;–content has loaded and is visible to the user.&lt;/p&gt;
&lt;p&gt;Lighthouse has a &amp;quot;Largest Contentful Paint element&amp;quot; audit that identifies what element was the
largest contentful paint. Hovering over the element will highlight it in the main browser window.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Largest Contentful Paint element&quot; decoding=&quot;async&quot; height=&quot;505&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/qeNJwYAVxysRV0okWmf4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;If this element is an image, this information is a useful hint that you may want to optimize the loading
of this image. Lighthouse includes a number of image optimization audits for helping you understand
if your images could be better compressed, resized or delivered in a more optimal modern image
format.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Properly size images audit&quot; decoding=&quot;async&quot; height=&quot;468&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/8RVIyj6NiMfx7VDVbQmI.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;You might also find &lt;a href=&quot;https://gist.github.com/anniesullie/cf2982342337fd1b2be95c2d5fe5ea06&quot; rel=&quot;noopener&quot;&gt;LCP
Bookmarklet&lt;/a&gt; by Annie
Sullivan useful for quickly identifying the LCP element with a red rectangle in just one click.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Highlighting the LCP element with a bookmarklet&quot; decoding=&quot;async&quot; height=&quot;509&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/eZJdYsdfsNniDW1KRJkE.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;preload-late-discovered-images-to-improve-lcp&quot;&gt;Preload late-discovered images to improve LCP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#preload-late-discovered-images-to-improve-lcp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To improve the Largest Contentful Paint, &lt;a href=&quot;https://web.dev/preload-responsive-images/&quot;&gt;preload&lt;/a&gt; your critical hero
images if they are being discovered late by the browser. A late discovery can happen if a
JavaScript bundle needs to be loaded before the image is discoverable.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Preload the largest contentful paint image&quot; decoding=&quot;async&quot; height=&quot;489&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K9EPBZdSFoyXVDHoDjTx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; &lt;strong&gt;Preload should be used sparingly&lt;/strong&gt;. Early network bandwidth is a scarce resource and using preload can come at the cost of another resource. To use preload effectively, make sure resources are being ordered correctly to avoid regressing other metrics when other resources in the page are also considered important (e.g. critical CSS, JS, fonts). The &lt;a href=&quot;https://docs.google.com/document/d/1ZEi-XXhpajrnq8oqs5SiW-CXR3jMc20jWIzN5QRy1QA/edit&quot;&gt;cost of preload&lt;/a&gt; covers this in more detail. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;There are a few common questions we are asked about preloading LCP images that may also be worth
briefly covering.&lt;/p&gt;
&lt;p&gt;Can you preload responsive images? &lt;a href=&quot;https://web.dev/preload-responsive-images/#imagesrcset-and-imagesizes&quot;&gt;Yes&lt;/a&gt;.
Let&#39;s say we have a responsive hero image as specified using &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; below:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lighthouse.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lighthouse_400px.jpg 400w,&lt;br /&gt;                  lighthouse_800px.jpg 800w,&lt;br /&gt;                  lighthouse_1600px.jpg 1600w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50vw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A helpful&lt;br /&gt;Lighthouse&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;Thanks to the &lt;code&gt;imagesrcset&lt;/code&gt; and &lt;code&gt;imagesizes&lt;/code&gt; attributes added to the &lt;code&gt;link&lt;/code&gt; attribute, we can
preload a responsive image using the same image selection logic used by &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lighthouse.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class=&quot;token attr-name&quot;&gt;imagesrcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lighthouse_400px.jpg 400w,&lt;br /&gt;                        lighthouse_800px.jpg 800w,&lt;br /&gt;                        lighthouse_1600px.jpg 1600w&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;imagesizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50vw&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;Will the audit also highlight preload opportunities if the LCP image is defined via a CSS
background? Yes.&lt;/p&gt;
&lt;p&gt;Any image flagged as the LCP image whether via CSS background or &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; is a candidate if it&#39;s
discovered at a waterfall depth of three or more.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-offscreen-images-and-avoiding-this-for-lcp&quot;&gt;Lazy loading offscreen images and avoiding this for LCP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#lazy-loading-offscreen-images-and-avoiding-this-for-lcp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Offscreen images that are not critical to the initial user experience can be &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/&quot;&gt;lazy-loaded&lt;/a&gt;. This is a technique that defers downloading an image until a user scrolls near it, which can reduce network contention for critical assets and in some cases improve LCP. The &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/offscreen-images/&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Defer offscreen images&amp;quot;&lt;/a&gt; audit can help here:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Defer offscreen images&quot; decoding=&quot;async&quot; height=&quot;317&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/vW6EwUnp51g0QVAkUyN9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Critical above-the-fold images, such as the Largest Contentful Paint image, should not be lazy loaded. Doing so can &lt;a href=&quot;https://web.dev/lcp-lazy-loading/&quot;&gt;delay the LCP image loading&lt;/a&gt;. Lighthouse will highlight if an LCP image is being incorrectly lazy-loaded via the &amp;quot;Largest Contentful Paint image was lazily loaded&amp;quot; audit:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Avoid lazy loading LCP images&quot; decoding=&quot;async&quot; height=&quot;226&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/VKmCrIG748sCCoByrBV8.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;identify-cls-contributions&quot;&gt;Identify CLS contributions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#identify-cls-contributions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cumulative Layout Shift is a measurement of visual stability. It quantifies how much a page&#39;s
content visually shifts around. Lighthouse has an audit for debugging CLS called &amp;quot;Avoid large
layout shifts&amp;quot;.&lt;/p&gt;
&lt;p&gt;This audit highlights DOM elements that contribute the most to shifts of the page. In the Element
column to the left you will see the list of these DOM elements and to the right, their overall CLS
contribution.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The avoid large layout shifts audit in Lighthouse highlighting relevant DOM nodes contributing to CLS&quot; decoding=&quot;async&quot; height=&quot;525&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/X31lkLFtfjDZdO2O7ytV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Thanks to the new Lighthouse Element Screenshots feature, we can both see a visual preview of the
key elements noted in the audit as well as click-to-zoom for a clearer view:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Clicking on an Element screenshot will expand it&quot; decoding=&quot;async&quot; height=&quot;525&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/L9geZVvkATRlAVcZA6dx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;For post-load CLS, there can be value in &lt;em&gt;persistently&lt;/em&gt; visualizing with rectangles
which elements contributed the most to CLS. This is a feature you&#39;ll find in third-party tools like
SpeedCurve&#39;s &lt;a href=&quot;https://speedcurve.com/blog/web-vitals-user-experience/&quot; rel=&quot;noopener&quot;&gt;Core Web Vitals dashboard&lt;/a&gt;
and which I love using &lt;a href=&quot;https://defaced.dev/tools/layout-shift-gif-generator/&quot; rel=&quot;noopener&quot;&gt;Defaced&#39;s Layout Shift GIF
Generator&lt;/a&gt; for:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;the layout shift generator highlighting shifts&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/ju6XjKBYzF6G537myjUW.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/ju6XjKBYzF6G537myjUW.gif?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;For a site-wide view of layout shift issues, I get a lot of mileage out of &lt;a href=&quot;https://support.google.com/webmasters/answer/9205520?hl=en&quot; rel=&quot;noopener&quot;&gt;Search Console&#39;s Core
Web Vitals report&lt;/a&gt;. This lets me see
the kinds of pages on my site with a high CLS (in this case helping self-identify what template
partials I need to spend my time on):&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Search Console displaying CLS issues&quot; decoding=&quot;async&quot; height=&quot;506&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/2Ihb2GYkbpGzYLYoZEDP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; To reduce layout shifts caused by Web Fonts, keep an eye on the new &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/blink-dev/c/1PVr94hZHjU/m/J0xT8-rlAQAJ&quot;&gt;size-adjust&lt;/a&gt; descriptor for &lt;code&gt;@font-face&lt;/code&gt;. This nable adjusting the size of fallback fonts to reduce CLS. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;identifying-cls-from-images-without-dimensions&quot;&gt;Identifying CLS from images without dimensions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#identifying-cls-from-images-without-dimensions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To &lt;a href=&quot;https://web.dev/optimize-cls/#images-without-dimensions&quot;&gt;limit&lt;/a&gt; Cumulative Layout Shift being caused by images
without dimensions, include width and height size attributes on your images and video elements.
This approach ensures that the browser can allocate the correct amount of space in the document
while the image is loading.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Audit for image elements without explicit width and height&quot; decoding=&quot;async&quot; height=&quot;489&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/fZRkmM18rvfy6y7LB1Qx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;See &lt;a href=&quot;https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/&quot; rel=&quot;noopener&quot;&gt;Setting Height And Width On Images Is Important
Again&lt;/a&gt; for a
good write-up on the importance of thinking about image dimensions and aspect ratio.&lt;/p&gt;
&lt;h3 id=&quot;identifying-cls-from-advertisements&quot;&gt;Identifying CLS from advertisements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#identifying-cls-from-advertisements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/publisher-ads-audits&quot; rel=&quot;noopener&quot;&gt;Publisher Ads for Lighthouse&lt;/a&gt; allows you to
find opportunities to improve the loading experience of ads on your page, including contributions
to layout shift and long tasks that may push out how soon your page is usable by users. In
Lighthouse, you can enable this via Community Plugins.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Ads related audits highlighting opportunities to reduce time to request and layout shift&quot; decoding=&quot;async&quot; height=&quot;527&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/kR3jgctso6Hg0OxD8xwi.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Remember that ads are one of the
&lt;a href=&quot;https://web.dev/optimize-cls/#ads-embeds-and-iframes-without-dimensions&quot;&gt;largest&lt;/a&gt; contributors to layout shifts
on the web. It&#39;s important to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take care when placing non-sticky ads near the top of the viewport&lt;/li&gt;
&lt;li&gt;Eliminate shifts by reserving the largest possible size for the ad slot&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;avoid-non-composited-animations&quot;&gt;Avoid non-composited animations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#avoid-non-composited-animations&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Animations which are non-composited can present themselves as janky on lower-end devices if heavy
JavaScript tasks are keeping the main thread busy. Such animations can introduce layout shifts.&lt;/p&gt;
&lt;p&gt;If Chrome discovers an animation couldn&#39;t be composited, it reports it to a DevTools trace
Lighthouse reads, allowing it to list which elements with animations weren&#39;t composited and for
what reason. You can find these in the &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; audit.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Audit for avoiding non-composited animations&quot; decoding=&quot;async&quot; height=&quot;528&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/heGuYXKeMrUftMvfrDU7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;debug-first-input-delay-total-blocking-time-long-tasks&quot;&gt;Debug First Input Delay / Total Blocking Time / Long Tasks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#debug-first-input-delay-total-blocking-time-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First Input measures the time from when a user first interacts with a page (e.g. when they click a
link, tap on a button, or use a custom, JavaScript-powered control) to the time when the browser is
actually able to begin processing event handlers in response to that interaction. Long JavaScript
Tasks can impact this metric and the proxy for this metric, Total Blocking Time.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Audit for avoiding long main thread tasks&quot; decoding=&quot;async&quot; height=&quot;485&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LqBCtAXdByd4fBzoNc1K.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Lighthouse includes an &lt;a href=&quot;https://web.dev/long-tasks-devtools/&quot;&gt;Avoid long main-thread tasks&lt;/a&gt; audit which lists the
longest tasks on the main thread. This can be helpful for identifying the worst contributors to
input delay. In the left column we can see the URL of scripts responsible for long main-thread
tasks.&lt;/p&gt;
&lt;p&gt;To the right we can see the duration of these tasks. As a reminder, Long Tasks are tasks which
execute for longer than 50 milliseconds. This is considered to block the main thread long enough to
impact frame rate or input latency.&lt;/p&gt;
&lt;p&gt;If considering third-party services for monitoring, I also quite like the &lt;a href=&quot;https://calibreapp.com/docs/features/main-thread-execution-timeline&quot; rel=&quot;noopener&quot;&gt;main-thread execution
timeline&lt;/a&gt; visual Calibre has
for visualizing these costs, which highlights both parent and child tasks contributing to long
tasks that impact interactivity.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The main-thread execution timeline visual Calibre has&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/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/IGENqHBjC97pHslOQYc6.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;block-network-requests-to-see-the-beforeafter-impact-in-lighthouse&quot;&gt;Block network requests to see the before/after impact in Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#block-network-requests-to-see-the-beforeafter-impact-in-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome DevTools supports &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/#block&quot; rel=&quot;noopener&quot;&gt;blocking network
requests&lt;/a&gt;
to see the impact of individual resources being removed or not being available. This can be helpful
for understanding the cost individual scripts (e.g such as third-party embeds or trackers) have on
metrics like Total Blocking Time (TBT) and Time to Interactive.&lt;/p&gt;
&lt;p&gt;Network request blocking happens to also work with Lighthouse! Let&#39;s take a quick look at the
Lighthouse report for a site. The Perf score is 63/100 with a TBT of 400ms. Digging into the code,
we find this site loads an Intersection Observer polyfill in Chrome which isn&#39;t necessary. Let&#39;s
block it!&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network request blocking&quot; decoding=&quot;async&quot; height=&quot;508&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/DPXEXhOZL0Czjm10lBox.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;We can right-click on a script in the DevTools Network panel and click &lt;code&gt;Block Request URL&lt;/code&gt; to block
it. Here we&#39;ll do this for the Intersection Observer polyfill.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Block request URLs in DevTools&quot; decoding=&quot;async&quot; height=&quot;354&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iWB0jAtL0PKpwkmecOPf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Next we can re-run Lighthouse. This time we can see our performance score has improved (70/100) as
has Total Blocking Time (400ms =&amp;gt; 300ms).&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The after view of blocking costly network requests&quot; decoding=&quot;async&quot; height=&quot;508&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/LiaMMxvy4prpFBIuSgfo.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;replace-costly-third-party-embeds-with-a-facade&quot;&gt;Replace costly third-party embeds with a facade &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#replace-costly-third-party-embeds-with-a-facade&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s common to use third-party resources for embedding videos, social media posts or widgets into
pages. By default, most embeds eagerly load right away and can come with costly payloads that
negatively impact the user-experience. This is wasteful if the third-party isn&#39;t critical (e.g. if
the user needs to scroll before they see it).&lt;/p&gt;
&lt;p&gt;One pattern to improve performance of such widgets is to &lt;a href=&quot;https://addyosmani.com/blog/import-on-interaction/&quot; rel=&quot;noopener&quot;&gt;lazy-load them on user
interaction&lt;/a&gt;. This can be done by rendering a
lightweight preview of the widget (a facade) and only load the full version if a user interacts
with it. Lighthouse has an audit that will recommend third-party resources which can be
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/&quot; rel=&quot;noopener&quot;&gt;lazy-loaded with a facade&lt;/a&gt;, such as YouTube video embeds.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Audit highlighting that some costly third party resources can be replaced&quot; decoding=&quot;async&quot; height=&quot;483&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/iciXy3oVlPH7VuwN7toy.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;As a reminder, Lighthouse will &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/third-party-summary/&quot; rel=&quot;noopener&quot;&gt;highlight third-party code&lt;/a&gt; that blocks the main thread for over 250ms. This can expose all kinds of third-party scripts (including ones authored by Google) that may be worth better deferring or lazy loading if what they render requires scrolling to view it.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Reduce the cost of third-party JavaScript audit&quot; decoding=&quot;async&quot; height=&quot;556&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/1L2RBhCLSnXjCnSlevaDjy3vba73/K0Oxmu1XEN2P3NQIknyH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;beyond-core-web-vitals&quot;&gt;Beyond Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-vitals-lighthouse/#beyond-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Beyond highlighting the Core Web Vitals, recent versions of Lighthouse and PageSpeed Insights also
try to provide concrete guidance you can follow for improving how quickly JavaScript-heavy web
applications can load if you have source maps turned on.&lt;/p&gt;
&lt;p&gt;These include a growing collection of audits for reducing the cost of JavaScript in your page, such
as reducing reliance on polyfills and duplicates that may not be needed for the user-experience.&lt;/p&gt;
&lt;p&gt;For more information on Core Web Vitals tooling, keep an eye on the &lt;a href=&quot;https://twitter.com/____lighthouse&quot; rel=&quot;noopener&quot;&gt;Lighthouse
team&lt;/a&gt; Twitter account and &lt;a href=&quot;https://developers.google.com/web/updates/2020/05/devtools&quot; rel=&quot;noopener&quot;&gt;What&#39;s new in
DevTools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://unsplash.com/photos/7I9aCavB8RI&quot; rel=&quot;noopener&quot;&gt;Hero image&lt;/a&gt; by
&lt;a href=&quot;https://unsplash.com/@mrs80z&quot; rel=&quot;noopener&quot;&gt;Mercedes Mehling&lt;/a&gt;
on &lt;a href=&quot;https://unsplash.com/&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>It&#39;s time to lazy-load offscreen iframes!</title>
    <link href="https://web.dev/iframe-lazy-loading/"/>
    <updated>2020-07-24T00:00:00Z</updated>
    <id>https://web.dev/iframe-lazy-loading/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/&quot;&gt;Standardized lazy-loading for images&lt;/a&gt; landed in Chrome 76 via
the &lt;code&gt;loading&lt;/code&gt; attribute and later came to Firefox. We are happy to share that
&lt;strong&gt;browser-level lazy-loading for iframes&lt;/strong&gt; is now
&lt;a href=&quot;https://github.com/whatwg/html/pull/5579&quot; rel=&quot;noopener&quot;&gt;standardized&lt;/a&gt; and is also
supported in Chrome and Chromium-based browsers.&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&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 attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;Standardized lazy-loading of iframes defers offscreen iframes from being loaded
until the user scrolls near them. This saves data, speeds up the loading of
other parts of the page, and reduces memory usage.&lt;/p&gt;
&lt;p&gt;This &lt;a href=&quot;https://lazy-load.netlify.app/iframes/&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; of &lt;code&gt;&amp;lt;iframe loading=lazy&amp;gt;&lt;/code&gt;
shows lazy-loading video embeds:&lt;/p&gt;
&lt;figure data-size=&quot;full&quot;&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/iframe-lazy-loading/lazyload-iframes-compressed.webm&quot; type=&quot;video/webm&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/iframe-lazy-loading/lazyload-iframes-compressed.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;why-should-we-lazy-load-iframes&quot;&gt;Why should we lazy-load iframes? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#why-should-we-lazy-load-iframes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Third-party embeds cover a wide range of use cases, from video players, to
social media posts, to ads. Often this content is not immediately visible in
the user&#39;s viewport. Rather, it&#39;s only seen once they scroll further down the
page. Despite this, users pay the cost of downloading data and costly
JavaScript for each frame, even if they don&#39;t scroll to it.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Data-savings from using iframe lazy-loading for an iframe. Eager loading pulls in 3MB in this example, while lazy-loading does not pull in this code until the user scrolls closer to the iframe.&quot; decoding=&quot;async&quot; height=&quot;460&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/xqZMRuULxbz6DVXNP8ea.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Based off Chrome&#39;s research into &lt;a href=&quot;https://blog.chromium.org/2019/10/automatically-lazy-loading-offscreen.html&quot; rel=&quot;noopener&quot;&gt;automatically lazy-loading offscreen iframes
for Data Saver
users&lt;/a&gt;,
lazy-loading iframes could lead to 2-3% median data savings, 1-2% &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First
Contentful Paint&lt;/a&gt; reductions at the median, and 2% &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input
Delay&lt;/a&gt; (FID) improvements at the 95th percentile.&lt;/p&gt;
&lt;p&gt;Additionally, lazy-loading off-screen iframes can impart benefits to &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt;.
&lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;LCP candidates&lt;/a&gt;, such as images or text dependent on web fonts
in order to render. Because iframes can often require a significant amount of bandwidth in
order to load all of their subresources, lazy-loading offscreen iframes can significantly
reduce bandwidth contention on network-constrained devices, leaving more bandwidth to load
resources which contribute to a page&#39;s LCP.&lt;/p&gt;
&lt;h3 id=&quot;how-does-built-in-lazy-loading-for-iframes-work&quot;&gt;How does built-in lazy-loading for iframes work? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#how-does-built-in-lazy-loading-for-iframes-work&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute allows a browser to defer loading offscreen iframes and
images until users scroll near them. &lt;code&gt;loading&lt;/code&gt; supports two values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lazy&lt;/code&gt;: is a good candidate for lazy-loading.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager&lt;/code&gt;: is not a good candidate for lazy-loading. Load right away.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the &lt;code&gt;loading&lt;/code&gt; attribute on iframes works as follows:&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 comment&quot;&gt;&amp;lt;!-- Lazy-load the iframe --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&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;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;600&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;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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 comment&quot;&gt;&amp;lt;!-- Eagerly load the iframe --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&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;600&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;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;Not specifying the attribute at all will have the same impact as explicitly
eagerly loading the resource.&lt;/p&gt;
&lt;p&gt;If you need to &lt;em&gt;dynamically&lt;/em&gt; create iframes via JavaScript, setting
&lt;code&gt;iframe.loading = &#39;lazy&#39;&lt;/code&gt; on the element is also
&lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=993273&quot; rel=&quot;noopener&quot;&gt;supported&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; iframe &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;iframe&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://example.com&#39;&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;iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loading &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lazy&#39;&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;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;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iframe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;iframe-specific-lazy-loading-behavior&quot;&gt;iframe-specific lazy-loading behavior &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#iframe-specific-lazy-loading-behavior&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The loading attribute affects iframes differently than images, depending on
whether the iframe is hidden. (Hidden iframes are often used for analytics or
communication purposes.) Chrome uses the following criteria to determine
whether an iframe is hidden:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The iframe&#39;s width and height are &lt;code&gt;4px&lt;/code&gt; or smaller.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display: none&lt;/code&gt; or &lt;code&gt;visibility: hidden&lt;/code&gt; is applied.&lt;/li&gt;
&lt;li&gt;The iframe is placed off-screen using negative X or Y positioning.&lt;/li&gt;
&lt;li&gt;This criteria applies to both &lt;code&gt;loading=lazy&lt;/code&gt; and &lt;code&gt;loading=auto&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If an iframe meets any of these conditions, Chrome considers it hidden and
won&#39;t lazy-load it in most cases. iframes that aren&#39;t hidden will only load
when they&#39;re within the &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#load-in-distance-threshold&quot;&gt;load-in distance
threshold&lt;/a&gt;. Chrome shows a
placeholder for lazy-loaded iframes that are still being fetched.&lt;/p&gt;
&lt;h3 id=&quot;what-impact-might-we-see-from-lazy-loading-popular-iframe-embeds&quot;&gt;What impact might we see from lazy-loading popular iframe embeds? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#what-impact-might-we-see-from-lazy-loading-popular-iframe-embeds&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What if we could change the web at large so that lazy-loading offscreen iframes
was the default? It would look a little like this:&lt;/p&gt;
&lt;p&gt;Lazy-loading YouTube video embeds (saves ~500KB on initial page load):&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/YJGCZCaIZkQ&lt;span class=&quot;token punctuation&quot;&gt;&quot;&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 attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;560&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;highlight-line&quot;&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;315&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;highlight-line&quot;&gt;        &lt;span class=&quot;token attr-name&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;accelerometer; autoplay;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        encrypted-media; gyroscope;&lt;/span&gt;&lt;br /&gt;        picture-in-picture&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;allowfullscreen&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;iframe&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;&lt;strong&gt;Anecdote:&lt;/strong&gt; when we switched to lazy-loading YouTube embeds for Chrome.com,
we saved 10 seconds off of how soon our pages could be interactive on mobile
devices. I have opened an internal bug with YouTube to discuss adding
&lt;code&gt;loading=lazy&lt;/code&gt; to its embed code.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Chrome.com achieved a 10 second reduction in Time To Interactive by lazy-loading offscreen iframes for their YouTube video embed&quot; decoding=&quot;async&quot; height=&quot;460&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/HQkwBgEoyiZsiOaPyz8v.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; If you are looking for more efficient ways to load YouTube embeds, you may be interested in the &lt;a href=&quot;https://github.com/paulirish/lite-youtube-embed&quot;&gt;YouTube lite component&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Lazy-loading Instagram embeds (saves &amp;gt;100KB gzipped on initial load):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instagram embeds provide a block of markup and a script, which injects an
iframe into your page. Lazy-loading this iframe avoids having to load all of
the script necessary for the embed. Given such embeds are often displayed below
the viewport in most articles, this seems like a reasonable candidate for
lazy-loading of their iframe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lazy-loading Spotify embeds (saves 514KB on initial load):&lt;/strong&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://open.spotify.com/embed/album/1DFixLWuPkv3KT3TnV35m3&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;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;300&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;380&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;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;allowtransparency&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;encrypted-media&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;iframe&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;Although the above embeds illustrate the potential benefits to lazy-loading
iframes for media content, there&#39;s the potential to also see these benefits for
ads.&lt;/p&gt;
&lt;h3 id=&quot;case-study-lazy-loading-the-facebooks-social-plugins&quot;&gt;Case study: Lazy-loading the Facebook&#39;s social plugins &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#case-study-lazy-loading-the-facebooks-social-plugins&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Facebook&#39;s &lt;em&gt;social plugins&lt;/em&gt; allow developers to embed Facebook content in their
web pages. There&#39;s a number of these plugins offered, such as embedded posts,
photos, videos, comments… The most popular is the &lt;a href=&quot;https://developers.facebook.com/docs/plugins/like-button/&quot; rel=&quot;noopener&quot;&gt;Like
plugin&lt;/a&gt; - a button
that shows a count of who has &amp;quot;liked&amp;quot; the page. By default, embedding the Like
plugin in a webpage (using the FB JSSDK) pulls in ~215KB of resources, 197KB of
which is JavaScript. In many cases, the plugin may appear at the end of an
article or near the end of a page, so loading it eagerly when it&#39;s offscreen
may be suboptimal.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Facebook Like Button&quot; decoding=&quot;async&quot; height=&quot;71&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/fdy8o61jxPN560IkF2Ne.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Thanks to engineer Stoyan Stefanov, &lt;a href=&quot;https://developers.facebook.com/docs/plugins/like-button#settings&quot; rel=&quot;noopener&quot;&gt;all of Facebook&#39;s social plugins now
support standardized iframe
lazy-loading&lt;/a&gt;.
Developers who opt in to lazy-loading via the plugins&#39; &lt;code&gt;data-lazy&lt;/code&gt;
configuration will now be able to avoid it loading until the user scrolls
nearby. This enables the embed to still fully function for users that need it,
while offering data-savings for those who are not scrolling all the way down a
page. We are hopeful this is the first of many embeds to explore standardized iframe
lazy-loading in production.&lt;/p&gt;
&lt;h3 id=&quot;can-i-lazy-load-iframes-cross-browser-yes&quot;&gt;Can I lazy-load iframes cross-browser? Yes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#can-i-lazy-load-iframes-cross-browser-yes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;iframe lazy-loading can be applied as a progressive enhancement. Browsers which support &lt;code&gt;loading=lazy&lt;/code&gt; on iframes will lazy-load the iframe, while the &lt;code&gt;loading&lt;/code&gt; attribute will be safely ignored in browsers which do not support it yet.&lt;/p&gt;
&lt;p&gt;It is also possible to lazy-load offscreen iframes using the
&lt;a href=&quot;https://web.dev/use-lazysizes-to-lazyload-images/&quot;&gt;lazysizes&lt;/a&gt; JavaScript library. This may be desirable if you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;require more custom lazy-loading thresholds than what standardized lazy-loading
currently offers&lt;/li&gt;
&lt;li&gt;wish to offer users a consistent iframe lazy-loading experience across browsers&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazysizes.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&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;lazyload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;data-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;//www.youtube.com/embed/ZfV-aYdU4uE&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;highlight-line&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;iframe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Use the following pattern to feature detect lazy-loading and fetch
lazysizes when it&#39;s not available:&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;lazyload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&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 attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;400&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;data-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;//www.youtube.com/embed/ZfV-aYdU4uE&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;highlight-line&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;iframe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;loading&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLIFrameElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; iframes &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;iframe[loading=&quot;lazy&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    iframes&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;iframe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;// Dynamically import the LazySizes library&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &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;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token string&quot;&gt;&#39;https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.2.2/lazysizes.min.js&#39;&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;    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;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;wordpress&quot;&gt;An option for WordPress users &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#wordpress&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You might have many iframes scattered across years worth of post content
in a WordPress site. You can optionally add the following code to your WordPress
theme&#39;s &lt;code&gt;functions.php&lt;/code&gt; file to automatically insert &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; to your
existing iframes without having to manually update them each individually.&lt;/p&gt;
&lt;p&gt;Note that &lt;a href=&quot;https://core.trac.wordpress.org/ticket/50756&quot; rel=&quot;noopener&quot;&gt;browser-level support for lazy-loading iframes is also being worked on in WordPress core&lt;/a&gt;.
The following snippet will check for the relevant flags so that, once WordPress has the
functionality built-in, it will no longer manually add the &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; attribute,
ensuring it is interoperable with those changes and will not result in a duplicate attribute.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// TODO: Remove once https://core.trac.wordpress.org/ticket/50756 lands.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;wp_lazy_load_iframes_polyfill&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token comment&quot;&gt;// If WP core lazy-loads iframes, skip this manual implementation.&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;function_exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;wp_lazy_loading_enabled&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_lazy_loading_enabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;iframe&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;the_content&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;str_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;iframe &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;iframe loading=&quot;lazy&quot; &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;add_filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;the_content&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;wp_lazy_load_iframes_polyfill&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If your WordPress site utilizes caching (hint: it should), don&#39;t forget to rebuild
your site&#39;s cache afterwards.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/iframe-lazy-loading/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Baking in standardized support for lazy-loading iframes makes it significantly
easier for you to improve the performance of your web pages. If you have any
feedback, please feel free to submit an issue to
the &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/entry?components=Blink%3ELoader%3ELazyLoad&quot; rel=&quot;noopener&quot;&gt;Chromium Bug
Tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And, in case you missed it, check out web.dev&#39;s &lt;a href=&quot;https://web.dev/fast/#lazy-load-images-and-video&quot;&gt;image and video lazy-loading
collection&lt;/a&gt; for more lazy-loading ideas.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Dom Farolino, Scott Little, Houssein Djirdeh, Simon Pieters, Kayce Basques, Joe Medley and Stoyan
Stefanov for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Prefetching in create-react-app with Quicklink</title>
    <link href="https://web.dev/codelab-quicklink/"/>
    <updated>2020-06-08T00:00:00Z</updated>
    <id>https://web.dev/codelab-quicklink/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses &lt;a href=&quot;https://www.google.com/chrome/&quot;&gt;Chrome DevTools&lt;/a&gt;. Download Chrome if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;This codelab shows you how to implement the &lt;a href=&quot;https://web.dev/quicklink&quot;&gt;Quicklink&lt;/a&gt; library in a React SPA demo to demonstrate how prefetching speeds up subsequent navigations.&lt;/p&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-quicklink/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before adding optimizations, it&#39;s always a good idea to first analyze the current state of the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Remix to Edit&lt;/strong&gt; to make the project editable.&lt;/li&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The website is a simple demo built with &lt;a href=&quot;https://reactjs.org/docs/create-a-new-react-app.html&quot; rel=&quot;noopener&quot;&gt;create-react-app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Complete the following instructions in the new tab that just opened:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;In the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/reference/#throttling&quot; rel=&quot;noopener&quot;&gt;Throttling drop-down list&lt;/a&gt;, select &lt;strong&gt;Fast 3G&lt;/strong&gt; to simulate a slow connection type.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;chunk&lt;/code&gt; into the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/reference/#filter-by-property&quot; rel=&quot;noopener&quot;&gt;Filter textbox&lt;/a&gt; to hide any resources that do not include &lt;code&gt;chunk&lt;/code&gt; in their name.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Network panel showing the home page chunks.&quot; decoding=&quot;async&quot; height=&quot;194&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/DCl6nkEfsVukurm8gBsy.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The site uses &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;route-based code splitting&lt;/a&gt;, thanks to which only the necessary code is requested at the beginning.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/reference/#clear&quot; rel=&quot;noopener&quot;&gt;Clear the network requests in DevTools&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Within the app, click the &lt;strong&gt;Blog&lt;/strong&gt; link to navigate to that page.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The JS and CSS chunks for the new route are loaded to render the page.&lt;/p&gt;
&lt;img alt=&quot;Network panel showing the blog page chunks.&quot; decoding=&quot;async&quot; height=&quot;119&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/23QuiFZwo7rouJaqmz9m.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Next, you&#39;ll implement Quicklink in this site, so that these chunks can be prefetched in the home page, making the navigation faster.&lt;/p&gt;
&lt;p&gt;This allows you to combine the best of both techniques:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Route-based code splitting tells the browser to only load the necessary chunks at a higher priority at page load time.&lt;/li&gt;
&lt;li&gt;Prefetching tells the browser to load the chunks for in-viewport links at the lowest priority, during the browser&#39;s idle time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;configure-webpack-route-manifest&quot;&gt;Configure &lt;code&gt;webpack-route-manifest&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-quicklink/#configure-webpack-route-manifest&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first step is to install and configure &lt;a href=&quot;https://github.com/lukeed/webpack-route-manifest&quot; rel=&quot;noopener&quot;&gt;webpack-route-manifest&lt;/a&gt;, a webpack plugin that lets you generate a manifest file associating routes with their corresponding chunks.&lt;/p&gt;
&lt;p&gt;Usually, you would need to install the library, but we&#39;ve already done it for you. Here&#39;s the command that you would need to run:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; webpack-route-manifest --save-dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;config-overrides.js&lt;/code&gt; is a file placed in your project root directory where you can override existing behaviour of the webpack configuration, without having to &lt;a href=&quot;https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/README.md#npm-run-eject&quot; rel=&quot;noopener&quot;&gt;eject the project&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To view the source, press &lt;strong&gt;View Source&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Open &lt;code&gt;config-overrides.js&lt;/code&gt; for edit and add the &lt;code&gt;webpack-route-manifest&lt;/code&gt; dependency at the beginning of the file:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; RouteManifest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;webpack-route-manifest&#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;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next, configure the &lt;code&gt;webpack-route-manifest&lt;/code&gt; plugin by adding the following
code to the bottom of &lt;code&gt;config-overrides.js&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resolve &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 operator&quot;&gt;...&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&#39;@assets&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/assets&#39;&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 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 string-property property&quot;&gt;&#39;@pages&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/pages&#39;&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 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 string-property property&quot;&gt;&#39;@components&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/components&#39;&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 template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;plugins&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;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RouteManifest&lt;/span&gt;&lt;span class=&quot;token punctuation&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;minify&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;filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;rmanifest.json&#39;&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;routes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; out &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; str&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;@pages&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#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;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;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;out &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/article&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/blog/:title&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/home&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; out&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The new code does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config.resolve&lt;/code&gt; declares variables with the internal routes to pages, assets and components.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config.plugins.push()&lt;/code&gt; creates a &lt;code&gt;RouteManifest&lt;/code&gt; object and passes it the configuration so that the &lt;code&gt;rmanifest.json&lt;/code&gt; file can be generated based on the site&#39;s routes and chunks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;manifest.json&lt;/code&gt; file will be generated and made available at &lt;code&gt;https://site_url/rmanifest.json&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;configure-quicklink&quot;&gt;Configure quicklink &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-quicklink/#configure-quicklink&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point you would need to install the Quicklink library in your project. For simplicity, we already added it to the project. Here&#39;s the command that you would need to run:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save quicklink&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Open &lt;code&gt;src/components/App/index.js&lt;/code&gt; for edit.&lt;/p&gt;
&lt;p&gt;First, import the Quicklink higher order component (HOC):&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense &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;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Route &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;react-router-dom&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Footer &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@components/Footer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Hero &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@components/Hero&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; style &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./index.module.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withQuicklink &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;quicklink/dist/react/hoc.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Home &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackChunkName: &quot;home&quot; */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@pages/Home&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; About &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackChunkName: &quot;about&quot; */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@pages/About&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Article &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackChunkName: &quot;article&quot; */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@pages/Article&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Blog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackChunkName: &quot;blog&quot; */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@pages/Blog&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next, create an &lt;code&gt;options&lt;/code&gt; object after the &lt;code&gt;Blog&lt;/code&gt; variable declaration, to use as an argument when calling &lt;code&gt;quicklink&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;origins&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;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Finally, wrap each route with the &lt;code&gt;withQuicklink()&lt;/code&gt; higher order component, passing it an &lt;code&gt;options&lt;/code&gt; parameter and the target component for that route:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&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;app&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Hero &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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main className&lt;span class=&quot;token operator&quot;&gt;=&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;wrapper&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Loading&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Route path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt; exact component&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 function&quot;&gt;withQuicklink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Home&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Route path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/blog&quot;&lt;/span&gt; exact component&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 function&quot;&gt;withQuicklink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Blog&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Route&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;          path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/blog/:title&quot;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;          component&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 function&quot;&gt;withQuicklink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Article&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&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;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Route path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/about&quot;&lt;/span&gt; exact component&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 function&quot;&gt;withQuicklink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;About&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Footer &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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The previous code instructs to prefetch chunks for the routes wrapped with &lt;code&gt;withQuicklink()&lt;/code&gt;, when the link comes into the view.&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 Glitch throws an error at this point about the lack of a dependency, try opening the Glitch Terminal (&lt;strong&gt;Tools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Terminal&lt;/strong&gt;), running &lt;code&gt;refresh&lt;/code&gt; in the Terminal, then running &lt;code&gt;npm run build&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;measure-again&quot;&gt;Measure again &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-quicklink/#measure-again&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Repeat the first 6 steps from &lt;a href=&quot;https://web.dev/codelab-quicklink/#measure&quot;&gt;Measure&lt;/a&gt;. Don&#39;t navigate to the blog page yet.&lt;/p&gt;
&lt;p&gt;When the home page loads the chunks for that route are loaded. After that, Quicklink prefetches the route&#39;s chunks for the in-viewport links:&lt;/p&gt;
&lt;img alt=&quot;Network panel showing the home page prefetching chunks.&quot; decoding=&quot;async&quot; height=&quot;286&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/lClOmOYDx8Cg3RZakAu2.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;These chunks are requested at the lowest priority and without blocking the page.&lt;/p&gt;
&lt;p&gt;Next:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clear the Network log again.&lt;/li&gt;
&lt;li&gt;Disable the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Blog&lt;/strong&gt; link to navigate to that page.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Network panel showing the blog page with chunks picked up from cache.&quot; decoding=&quot;async&quot; height=&quot;95&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bJJYT3gDIWU9PeeXSdOE.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The &lt;strong&gt;Size&lt;/strong&gt; column indicates that these chunks were retrieved from the &amp;quot;prefetch cache&amp;quot;, instead of the network. Loading these chunks without a Quicklink took approximately &lt;strong&gt;580ms&lt;/strong&gt;. Using the library it now takes &lt;strong&gt;2ms&lt;/strong&gt;, which represents a &lt;strong&gt;99% reduction&lt;/strong&gt;!&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Demian Renzulli</name>
    </author><author>
      <name>Anton Karlovskiy</name>
    </author>
  </entry>
  
  <entry>
    <title>Speed up navigations in React with Quicklink</title>
    <link href="https://web.dev/quicklink/"/>
    <updated>2020-06-08T00:00:00Z</updated>
    <id>https://web.dev/quicklink/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://web.dev/link-prefetch/&quot;&gt;Prefetching&lt;/a&gt; is a technique to speed up navigations by downloading the resources for the next page, ahead of time. &lt;a href=&quot;https://github.com/GoogleChromeLabs/quicklink&quot; rel=&quot;noopener&quot;&gt;Quicklink&lt;/a&gt; is a library that allows you to implement this technique at scale, by automatically prefetching links as they come into the view.&lt;/p&gt;
&lt;p&gt;In multi-page apps the library prefetches documents (e.g. &lt;code&gt;/article.html&lt;/code&gt;), for in-viewport links, so that when the user clicks on these links they can be picked up from the &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;HTTP cache&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Single-page_application&quot; rel=&quot;noopener&quot;&gt;Single-page apps&lt;/a&gt; commonly use a technique called &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;route-based code splitting&lt;/a&gt;. This allows the site to load the code for a given route only when the user navigates to it. These files (JS, CSS) are commonly referred to as &amp;quot;chunks&amp;quot;.&lt;/p&gt;
&lt;p&gt;With that said, in these sites, instead of prefetching documents the biggest performance gains come from prefetching these chunks before the page needs them.&lt;/p&gt;
&lt;p&gt;Achieving this presents some challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&#39;s not trivial to determine which chunks (e.g. &lt;code&gt;article.chunk.js&lt;/code&gt;) are associated with a given route (e.g. &lt;code&gt;/article&lt;/code&gt;) before landing on it.&lt;/li&gt;
&lt;li&gt;The final URL names of these chunks can&#39;t be predicted, as modern module bundlers typically use long-term hashing for versioning (e.g. &lt;code&gt;article.chunk.46e51.js&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide explains how Quicklink solves these challenges and allows you to achieve prefetching at scale in React single page apps.&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; At the moment this solution is only compatible with &lt;a href=&quot;https://www.npmjs.com/package/react-router&quot;&gt;react-router&lt;/a&gt;. &lt;/div&gt;&lt;/aside&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; Check out the &lt;a href=&quot;https://web.dev/codelab-quicklink/&quot;&gt;Prefetching in create-react-app with Quicklink&lt;/a&gt; codelab for a guided, hands-on demonstration of Quicklink. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;determine-chunks-associated-with-each-route&quot;&gt;Determine chunks associated with each route &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/quicklink/#determine-chunks-associated-with-each-route&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the core components of &lt;code&gt;quicklink&lt;/code&gt; is &lt;a href=&quot;https://github.com/lukeed/webpack-route-manifest&quot; rel=&quot;noopener&quot;&gt;webpack-route-manifest&lt;/a&gt;, a &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; plugin that lets you generate a JSON dictionary of routes and chunks.
This allows the library to know which files are going to be needed by each route of the application and prefetch them as the routes come into the view.&lt;/p&gt;
&lt;p&gt;After &lt;a href=&quot;https://github.com/lukeed/webpack-route-manifest#install&quot; rel=&quot;noopener&quot;&gt;integrating the plugin&lt;/a&gt; with the project, it will produce a JSON manifest file associating each route with its corresponding chunks:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&#39;/about&#39;&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 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;style&#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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/css/about.f6fd7d80.chunk.css&#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;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;script&#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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/js/about.1cdfef3b.chunk.js&#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;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&#39;/blog&#39;&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 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;style&#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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/css/blog.85e80e75.chunk.css&#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;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;script&#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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/js/blog.35421503.chunk.js&#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;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 manifest file can be requested in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By URL, e.g. &lt;code&gt;https://site_url/rmanifest.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Through the window object, at &lt;code&gt;window.__rmanifest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prefetch-chunks-for-in-viewport-routes&quot;&gt;Prefetch chunks for in-viewport routes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/quicklink/#prefetch-chunks-for-in-viewport-routes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the manifest file is available, the next step is to install Quicklink by running &lt;code&gt;npm install quicklink&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, the &lt;a href=&quot;https://reactjs.org/docs/higher-order-components.html&quot; rel=&quot;noopener&quot;&gt;higher order component (HOC)&lt;/a&gt; &lt;code&gt;withQuicklink()&lt;/code&gt; can be used to indicate that a given route should be prefetched when the link comes into the view.&lt;/p&gt;
&lt;p&gt;The following code belongs to an &lt;code&gt;App&lt;/code&gt; component of a React app that renders a top menu with four links:&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&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 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;className&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;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Hero&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 plain-text&quot;&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;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&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;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wrapper&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fallback&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;&lt;span class=&quot;token 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;span class=&quot;token plain-text&quot;&gt;Loading…&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;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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Route&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&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;Home&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Route&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/blog&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&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;Blog&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Route&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/blog/:title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&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;Article&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Route&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/about&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&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;About&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;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&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 plain-text&quot;&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;main&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;    &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;&lt;span class=&quot;token class-name&quot;&gt;Footer&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 plain-text&quot;&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;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 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;To tell Quicklink that these routes should be prefetched as they come into the view:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the &lt;code&gt;quicklink&lt;/code&gt; HOC at the beginning of the component.&lt;/li&gt;
&lt;li&gt;Wrap each route with the &lt;code&gt;withQuicklink()&lt;/code&gt; HOC, passing the page component and options parameter to it.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;const options = {&lt;br /&gt;  origins: [],&lt;br /&gt;};&lt;br /&gt;const App = () =&gt; (&lt;br /&gt;  &lt;span class=&quot;token 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;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{style.app}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Hero&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{style.wrapper}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Suspense&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fallback&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{&amp;lt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Loading…&lt;span class=&quot;token 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;}&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Route&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{withQuicklink(Home,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;options)}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Route&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/blog&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{withQuicklink(Blog,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;options)}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Route&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/blog/:title&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;component&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{withQuicklink(Article,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;options)}&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;Route&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/about&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;{withQuicklink(About,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;options)}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Suspense&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Footer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;withQuicklink()&lt;/code&gt; HOC uses the path of the route as a key to obtain its associated chunks from &lt;code&gt;rmanifest.json&lt;/code&gt;.
Under the hood, as links come into the view, the library injects a &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tag in the page for each chunk so they can be prefetched.
Prefetched resources will be requested at the lowest priority by the browser and kept in the &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;HTTP Cache&lt;/a&gt; for 5 minutes, after which point, the &lt;code&gt;cache-control&lt;/code&gt; rules of the resource apply.
As a result of this, when a user clicks on a link and moves to a given route, the chunks will be retrieved from the cache, greatly improving the time it takes to render that route.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/quicklink/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Prefetching can greatly improve load times for future navigations. In React single-page apps, this can be achieved by loading the chunks associated with each route, before the user lands in them.
Quicklink&#39;s solution for React SPA uses &lt;code&gt;webpack-route-manifest&lt;/code&gt; to create a map of routes and chunks, in order to determine which files to prefetch, when a link comes into the view.
Implementing this technique throughout your site can greatly improve navigations to the point of making them appear instant.&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Demian Renzulli</name>
    </author><author>
      <name>Anton Karlovskiy</name>
    </author>
  </entry>
  
  <entry>
    <title>Tools to measure Core Web Vitals</title>
    <link href="https://web.dev/vitals-tools-2020/"/>
    <updated>2020-05-28T00:00:00Z</updated>
    <id>https://web.dev/vitals-tools-2020/</id>
    <content type="html" mode="escaped">&lt;p&gt;The recently announced &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Web Vitals&lt;/a&gt; initiative provides unified guidance about quality signals that are essential for all sites to deliver a great user experience on the web. We&#39;re happy to announce that &lt;strong&gt;all of Google&#39;s popular tools for web developers now support measurement of Core Web Vitals&lt;/strong&gt;, helping you more easily diagnose and fix user experience issues. This includes &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;, &lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt;, &lt;a href=&quot;https://search.google.com/search-console/about&quot; rel=&quot;noopener&quot;&gt;Search Console&lt;/a&gt;, &lt;a href=&quot;https://web.dev/measure/&quot;&gt;web.dev&#39;s measure tool&lt;/a&gt;, the &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot; rel=&quot;noopener&quot;&gt;Web Vitals Chrome extension&lt;/a&gt; and a new (!) &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome UX Report&lt;/a&gt; API.&lt;/p&gt;
&lt;p&gt;With Google Search now including Core Web Vitals as the foundation for evaluating &lt;a href=&quot;https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html&quot; rel=&quot;noopener&quot;&gt;page experience&lt;/a&gt;, it&#39;s important that these metrics are as available and actionable as possible.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Summary of Chrome and Search Tools that support the Core Web Vitals metrics&quot; decoding=&quot;async&quot; height=&quot;509&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/V00vjrHmwzljYo04f3d3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow color-secondary-box-text bg-secondary-box-bg&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;Highlighter pen&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;M10.22 9.49l-5.91 6c-.77.8-.7 2.05.08 2.85L.77 22h5.68l.74-.75c.78.81 1.95.86 2.73.05l5.96-6.05-5.66-5.76zm12.46-4l-2.82-2.87c-.78-.8-2.07-.84-2.84-.04l-5.75 5.85 5.66 5.75 5.69-5.78c.77-.81.83-2.11.06-2.91z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Key Term&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;strong&gt;Lab tools&lt;/strong&gt; provide insight into how a &lt;em&gt;potential user&lt;/em&gt; will likely experience your website and offer reproducible results for debugging. &lt;strong&gt;Field&lt;/strong&gt; tools provide insight into how your &lt;em&gt;real users&lt;/em&gt; are experiencing your website; this type of measurement is often called Real User Monitoring (RUM). Each &lt;a href=&quot;https://web.dev/how-to-measure-speed/#lab-data-vs-field-data&quot;&gt;lab or field tool&lt;/a&gt; offers distinct value for optimizing your user experience. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;To begin your journey optimizing user-experience with Core Web Vitals, try the following workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Search Console&#39;s new Core Web Vitals report to identify groups of pages that require attention (based on the field data).&lt;/li&gt;
&lt;li&gt;Once you&#39;ve identified pages that need work, use PageSpeed Insights (powered by Lighthouse and Chrome UX Report) to diagnose lab and field issues on a page. PageSpeed Insights (PSI) is available via Search Console or you can enter a URL on PSI directly.&lt;/li&gt;
&lt;li&gt;Ready to optimize your site locally in the lab? Use Lighthouse and Chrome DevTools to measure Core Web Vitals and get actionable guidance on exactly what to fix. The Web Vitals Chrome extension can give you a real-time view of metrics on desktop.&lt;/li&gt;
&lt;li&gt;Need a custom dashboard of Core Web Vitals? Use the updated CrUX Dashboard or new Chrome UX Report API for field data or PageSpeed Insights API for lab data.&lt;/li&gt;
&lt;li&gt;Looking for guidance? web.dev/measure can measure your page and show you a prioritized set of guides and codelabs for optimization, using PSI data.&lt;/li&gt;
&lt;li&gt;Finally, use Lighthouse CI on pull requests to ensure there are no regressions in Core Web Vitals before you deploy a change to production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that introduction, let&#39;s dive into the specific updates for each tool!&lt;/p&gt;
&lt;h3 id=&quot;lighthouse&quot;&gt;Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lighthouse is an automated website auditing tool that helps developers diagnose issues and identify opportunities to improve the user experience of their sites. It measures several dimensions of user experience quality in a lab environment, including performance and accessibility. The latest version of Lighthouse (&lt;a href=&quot;https://web.dev/lighthouse-whats-new-6.0/&quot;&gt;6.0&lt;/a&gt;, released mid-May 2020) includes additional audits, new metrics, and a newly composed performance score.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse 6.0 showing the latest Core Web Vitals metrics&quot; decoding=&quot;async&quot; height=&quot;527&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/4j72CWywp2D88Xti8zBf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Lighthouse 6.0 introduces three new metrics to the report. Two of these new metrics—&lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt; (LCP) and &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift&lt;/a&gt; (CLS)—are lab implementations of Core Web Vitals and provide important diagnostic information for optimizing user experience. Given their importance for assessing user experience, the new metrics are not only measured and included in the report, they are also factored in calculating the performance score.&lt;/p&gt;
&lt;p&gt;The third new metric included in Lighthouse—&lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time&lt;/a&gt; (TBT)—correlates well with the field metric &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt; (FID), another Core Web Vitals metric. Following the recommendations provided in the Lighthouse report and optimizing against your scores sets you up to provide the best possible experience to your users.&lt;/p&gt;
&lt;p&gt;All of the products that Lighthouse powers are updated to reflect the latest version, including &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; rel=&quot;noopener&quot;&gt;Lighthouse CI&lt;/a&gt; which enables you to easily measure your Core Web Vitals on pull requests before they&#39;re merged and deployed.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse CI displaying a diff view with Largest Contentful Paint&quot; decoding=&quot;async&quot; height=&quot;498&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/aOm5ZAIUbspjcyRMIXbn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To learn more about the latest updates to Lighthouse, check out our
&lt;a href=&quot;https://web.dev/lighthouse-whats-new-6.0/&quot;&gt;What&#39;s New in Lighthouse 6.0&lt;/a&gt; blog post.&lt;/p&gt;
&lt;h3 id=&quot;pagespeed-insights&quot;&gt;PageSpeed Insights &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#pagespeed-insights&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; (PSI) reports on the lab and field performance of a page on both mobile and desktop devices. The tool provides an overview of how real-world users experience the page (powered by the Chrome UX Report) and a set of actionable recommendations on how a site owner can improve page experience (provided by Lighthouse).&lt;/p&gt;
&lt;p&gt;PageSpeed Insights and the &lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/get-started&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights API&lt;/a&gt; have also been upgraded to use Lighthouse 6.0 under the hood and now support measuring Core Web Vitals in both the lab and field sections of the report! Core Web Vitals are annotated with a blue ribbon as shown below.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;PageSpeed Insights with Core Web Vitals data displayed for field and lab&quot; decoding=&quot;async&quot; height=&quot;873&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/l1posckVsR7JeVGnk6Jv.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;While &lt;a href=&quot;https://search.google.com/search-console/&quot; rel=&quot;noopener&quot;&gt;Search Console&lt;/a&gt; provides site owners with a great overview of groups of pages that need attention, PSI helps identify per-page opportunities to improve page experience. In PSI, you are able to clearly see whether or not your page meets the thresholds for a good experience across all Core Web Vitals at the top of the report, indicated by &lt;strong&gt;passes the Core Web Vitals assessment&lt;/strong&gt; or &lt;strong&gt;does not pass the Core Web Vitals assessment&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;crux&quot;&gt;CrUX &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#crux&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome UX Report&lt;/a&gt; (CrUX) is a public dataset of real user experience data on millions of websites. It measures field versions of all the Core Web Vitals. Unlike lab data, CrUX data comes from &lt;a href=&quot;https://developer.chrome.com/docs/crux/methodology/#user-eligibility&quot; rel=&quot;noopener&quot;&gt;opted-in users&lt;/a&gt; in the field. Using this data, developers are able to understand the distribution of real-world user experiences on their own or even competitors&#39; websites. Even if you don&#39;t have RUM on your site, CrUX can provide a quick and easy way to assess your Core Web Vitals. The &lt;a href=&quot;https://developer.chrome.com/docs/crux/bigquery/&quot; rel=&quot;noopener&quot;&gt;CrUX dataset on BigQuery&lt;/a&gt; includes fine-grained performance data for all Core Web Vitals and is available in monthly snapshots at the origin-level.&lt;/p&gt;
&lt;p&gt;The only way to truly know how your site performs for your users is to actually measure its performance in the field as those users are loading and interacting with it. This type of measurement is commonly referred to as Real User Monitoring—or RUM for short. Even if you don&#39;t have RUM on your site, CrUX can provide a quick and easy way to assess your Core Web Vitals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introducing the CrUX API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Today we&#39;re happy to announce the &lt;a href=&quot;http://developers.google.com/web/tools/chrome-user-experience-report/api/reference/&quot; rel=&quot;noopener&quot;&gt;CrUX API&lt;/a&gt;, a fast and free way to easily integrate your development workflows with origin and URL-level quality measurement for the following field metrics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Largest Contentful Paint&lt;/li&gt;
&lt;li&gt;Cumulative Layout Shift&lt;/li&gt;
&lt;li&gt;First Input Delay&lt;/li&gt;
&lt;li&gt;First Contentful Paint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Developers can query for an origin or URL and segment results by different form factors. The API updates daily and summarizes the previous 28 days worth of data (unlike the BigQuery dataset, which is aggregated monthly). The API also has the same relaxed public API quotas we place on our other API, the PageSpeed Insights API (25,000 requests per day).&lt;/p&gt;
&lt;p&gt;Below is a demo using the &lt;a href=&quot;https://developer.chrome.com/docs/crux/api/&quot; rel=&quot;noopener&quot;&gt;CrUX API&lt;/a&gt; to visualize the Core Web Vitals metrics with distributions for &lt;strong&gt;good&lt;/strong&gt;, &lt;strong&gt;needs improvement&lt;/strong&gt;, and &lt;strong&gt;poor&lt;/strong&gt;:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Chrome User Experience Report API demo showing Core Web Vitals metrics&quot; decoding=&quot;async&quot; height=&quot;523&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ye3CMKfacSItYA2lqItP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;In future releases, we plan to expand the API to enable access to additional CrUX dataset dimensions and metrics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Revamped CrUX Dashboard&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The newly redesigned &lt;a href=&quot;http://g.co/chromeuxdash&quot; rel=&quot;noopener&quot;&gt;CrUX Dashboard&lt;/a&gt; allows you to easily track an origin&#39;s performance over time, and now you can use it to monitor the distributions of all of the Core Web Vitals metrics. To get started with the dashboard, check out our &lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-looker-studio-dashboard/&quot; rel=&quot;noopener&quot;&gt;tutorial&lt;/a&gt; on web.dev.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Chrome UX Report dashboard displaying the Core Web Vitals metrics in a new landing page&quot; decoding=&quot;async&quot; height=&quot;497&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/OjbICyhI21RNfGXrFP1x.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;We&#39;ve introduced a new Core Web Vitals landing page to make it even easier to see how your site is performing at a glance. We welcome your feedback on all CrUX tooling; to share your thoughts and questions reach us at the &lt;a href=&quot;https://twitter.com/chromeuxreport&quot; rel=&quot;noopener&quot;&gt;@ChromeUXReport&lt;/a&gt; Twitter account or &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/chrome-ux-report&quot; rel=&quot;noopener&quot;&gt;Google Group&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;chrome-devtools-performance-panel&quot;&gt;Chrome DevTools Performance panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#chrome-devtools-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Debug Layout Shift events in the Experience section&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Chrome DevTools &lt;strong&gt;Performance&lt;/strong&gt; panel has a new &lt;strong&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2020/05/devtools#cls&quot; rel=&quot;noopener&quot;&gt;Experience section&lt;/a&gt;&lt;/strong&gt; that can help you detect unexpected layout shifts. This is helpful for finding and fixing visual instability issues on your page that contribute to Cumulative Layout Shift.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Cumulative Layout Shift displayed with red records in the Performance panel&quot; decoding=&quot;async&quot; height=&quot;517&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/VMbZAgKCi5V6FiQyu631.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Select a Layout Shift to view its details in the &lt;strong&gt;Summary&lt;/strong&gt; tab. To visualize where the shift itself occurred, hover over the &lt;strong&gt;Moved from&lt;/strong&gt; and &lt;strong&gt;Moved to&lt;/strong&gt; fields.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debug interaction readiness with Total Blocking Time in the footer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Total Blocking Time (TBT) metric can be measured in lab tools and is an excellent proxy for First Input Delay. TBT measures the total amount of time between &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint (FCP)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/tti/&quot;&gt;Time to Interactive (TTI)&lt;/a&gt; where the main thread was blocked for long enough to prevent input responsiveness. Performance optimizations that improve TBT in the lab should improve FID in the field.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Total Blocking Time displayed in the footer of the DevTools performance panel&quot; decoding=&quot;async&quot; height=&quot;517&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/WufuLpvrZfgbRn70C74V.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;TBT is now shown in the footer of the Chrome DevTools &lt;strong&gt;Performance&lt;/strong&gt; panel when you measure page performance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Performance&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Record&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Manually reload the page.&lt;/li&gt;
&lt;li&gt;Wait for the page to load and then stop recording.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information, see &lt;a href=&quot;https://developers.google.com/web/updates/2020/05/devtools#cls&quot; rel=&quot;noopener&quot;&gt;What&#39;s New In DevTools (Chrome 84)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;search-console&quot;&gt;Search Console &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#search-console&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The new &lt;a href=&quot;https://support.google.com/webmasters/answer/9205520&quot; rel=&quot;noopener&quot;&gt;Core Web Vitals report&lt;/a&gt; in Search Console helps you identify groups of pages across your site that require attention, based on real-world (field) data from CrUX. URL performance is grouped by status, metric type and URL group (groups of similar web pages).&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Search Console&amp;#x27;s new Core Web Vitals Report&quot; decoding=&quot;async&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/BjTUt0xdWXD9hrLsbhLK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The report is based on the three Core Web Vitals metrics: LCP, FID, and CLS.  If a URL does not have a minimum amount of reporting data for these metrics, it&#39;s omitted from the report. Try the new report to get a holistic view of performance for your origin.&lt;/p&gt;
&lt;p&gt;Once you identify a type of page that has Core Web Vitals related issues, you can use PageSpeed Insights to learn about specific optimization suggestions for representative pages.&lt;/p&gt;
&lt;h4 id=&quot;webdev&quot;&gt;web.dev &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#webdev&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/measure/&quot;&gt;web.dev/measure&lt;/a&gt; allows you to measure the performance of your page over time, providing a prioritized list of guides and codelabs on how to improve. It&#39;s measurement is powered by PageSpeed Insights. The measure tool now also supports the Core Web Vitals metrics, as shown below:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Measure Core Web Vitals metrics over time and get prioritized guidance with the web.dev measure tool&quot; decoding=&quot;async&quot; height=&quot;459&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ryoV1T1PhxUmo9zdCsDe.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;web-vitals-extension&quot;&gt;Web Vitals extension &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#web-vitals-extension&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Web Vitals extension measures the three Core Web Vitals metrics in real-time for (desktop) Google Chrome. This is helpful for catching issues early on during your development workflow and as a diagnostic tool to assess performance of Core Web Vitals as you browse the web.&lt;/p&gt;
&lt;p&gt;The extension is now available to install from the &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma?hl=en&quot; rel=&quot;noopener&quot;&gt;Chrome Web Store&lt;/a&gt;! We hope you find it useful. We welcome any contributions to improve it as well as feedback on the project&#39;s &lt;a href=&quot;https://github.com/GoogleChrome/web-vitals-extension/&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; repository.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Core Web Vitals displayed in real-time with the Web Vitals Chrome Extension&quot; decoding=&quot;async&quot; height=&quot;459&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/woROdEmNV4jlHDPryjBQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;quick-highlights&quot;&gt;Quick highlights &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-tools-2020/#quick-highlights&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;That&#39;s a wrap! What can you do next:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Lighthouse&lt;/strong&gt; in DevTools to optimize your user experience and ensure you are setting yourself up for success with Core Web Vitals in the field.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;PageSpeed Insights&lt;/strong&gt; to compare your lab and field Core Web Vitals performance.&lt;/li&gt;
&lt;li&gt;Try out the new &lt;strong&gt;Chrome User Experience Report API&lt;/strong&gt; to easily access how well your origin and URL have performed against Core Web Vitals over the last 28 days.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Experience&lt;/strong&gt; section and footer in DevTools &lt;strong&gt;Performance&lt;/strong&gt; panel to dive deep and debug against specific Core Web Vitals.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Search Console&#39;s Core Web Vitals report&lt;/strong&gt; for a summary of how your origins are performing in the field.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Web Vitals Extension&lt;/strong&gt; to track a page&#39;s performance against Core Web Vitals in real-time.&lt;/li&gt;
&lt;/ul&gt;
&lt;dl&gt;
&lt;dt&gt;We will cover more about our Core Web Vitals tooling at &lt;a href=&quot;https://web.dev/live/&quot;&gt;web.dev Live&lt;/a&gt; in June. Sign up to get updates on the event!&lt;/dt&gt;
&lt;dd&gt;by Elizabeth and Addy, WebPerf Janitors&lt;/dd&gt;
&lt;/dl&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Elizabeth Sweeny</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimize Cumulative Layout Shift</title>
    <link href="https://web.dev/optimize-cls/"/>
    <updated>2020-05-05T00:00:00Z</updated>
    <id>https://web.dev/optimize-cls/</id>
    <content type="html" mode="escaped">&lt;p&gt;&amp;quot;I was about to click that! Why did it move? 😭&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt; is one of the three &lt;a href=&quot;https://web.dev/vitals/#core-web-vitals&quot;&gt;Core Web Vitals&lt;/a&gt; metrics, and it measures the instability of content by summing shift scores across layout shifts that don&#39;t occur within 500 milliseconds of user input. It looks at how much visible content shifted in the viewport as well as the distance the elements impacted were shifted.&lt;/p&gt;
&lt;p&gt;Layout shifts can be distracting to users. Imagine you&#39;ve started reading an article when all of a sudden elements shift around the page, throwing you off and requiring you to find your place again. This is very common on the web, including when reading the news, or trying to click those &#39;Search&#39; or &#39;Add to Cart&#39; buttons. Such experiences are visually jarring and frustrating. They&#39;re often caused when visible elements are forced to move because another element was suddenly added to the page or resized.&lt;/p&gt;
&lt;p&gt;To provide a good user experience, &lt;strong&gt;sites should strive to have a CLS of 0.1 or less for at least 75% of page visits.&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
  &lt;picture&gt;
    &lt;source srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/9mWVASbWDLzdBUpVcjE1.svg&quot; media=&quot;(min-width: 640px)&quot; width=&quot;800&quot; height=&quot;200&quot; /&gt;
    &lt;img alt=&quot;Good CLS values are under 0.1, poor values are greater than 0.25 and anything in between needs improvement&quot; decoding=&quot;async&quot; height=&quot;480&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/uqclEgIlTHhwIgNTXN3Y.svg&quot; width=&quot;640&quot; /&gt;
  &lt;/picture&gt;
&lt;/figure&gt;
&lt;p&gt;Unlike the other Core Web Vitals, which are time-based values measured in seconds or milliseconds, the CLS score is a unitless value based on a calculation of how much content is shifting and by how far.&lt;/p&gt;
&lt;p&gt;In this guide, we&#39;ll cover optimizing common causes of layout shifts.&lt;/p&gt;
&lt;p&gt;The most common causes of a poor CLS are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Images without dimensions&lt;/li&gt;
&lt;li&gt;Ads, embeds, and iframes without dimensions&lt;/li&gt;
&lt;li&gt;Dynamically injected content such as ads, embeds, and iframes without dimensions&lt;/li&gt;
&lt;li&gt;Web fonts&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; For a visual overview of some of the content presented in this guide, see the Optimize for Core Web Vitals video from Google I/O 2020:  &lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;AQqFZ5t8uNc&quot; videoStartAt=&quot;88&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;understanding-where-your-shifts-are-coming-from&quot;&gt;Understanding where your shifts are coming from &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#understanding-where-your-shifts-are-coming-from&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start looking at solutions to common CLS issues, it&#39;s always important to understand your CLS score and where the shifts are coming from. A big part of the problem is understanding your CLS score—the fix afterwards is often the easier part!&lt;/p&gt;
&lt;h3 id=&quot;cls-in-lab-tools-versus-field&quot;&gt;CLS in lab tools versus field &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#cls-in-lab-tools-versus-field&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is quite common to hear developers think the CLS measured by the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome UX Report (CrUX)&lt;/a&gt; is incorrect as it does not match the CLS they measure using Chrome DevTools or other lab tools. Web performance lab tools like Lighthouse may not show the full CLS of a page as they typically do a simple load of the page to measure some web performance metrics and provide some guidance (though &lt;a href=&quot;https://web.dev/lighthouse-user-flows/&quot;&gt;Lighthouse user flows&lt;/a&gt; do allow you measure beyond the default page load audit).&lt;/p&gt;
&lt;p&gt;CrUX is the official dataset of the Web Vitals program, and for that, CLS is measured throughout the full life of the page and not just during the initial page load that lab tools typically measure.&lt;/p&gt;
&lt;p&gt;Layout shifts are very common during page load, as all the necessary resources are fetched to initially render the page, but layout shifts can also happen after the initial load. Many post-load shifts may occur &lt;a href=&quot;https://web.dev/cls/#user-initiated-layout-shifts&quot;&gt;as the result of a user interaction&lt;/a&gt; and therefore will be excluded from the CLS score as they are &lt;em&gt;expected&lt;/em&gt; shifts—as long as they occur within 500 milliseconds of that interaction.&lt;/p&gt;
&lt;p&gt;However, other post-load shifts that are unexpected by the user may be included where there was no qualifying interaction—for example, if you scroll down the page and lazy-loaded content is loaded and that causes shifts. Other common causes of post-load CLS are on interactions of transitions, for example on Single Page Apps, which take longer than the 500 millisecond grace period.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; will show both the user-perceived CLS from a URL where it exists in the &amp;quot;Discover what your real users are experiencing&amp;quot; section, and also the lab-based load CLS in the &amp;quot;Diagnose performance issues&amp;quot; section beneath. If you see a difference between these, this is likely caused by post-load CLS.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of PageSpeed Insights showing URL-level data highlighting the real user CLS which is considerably larger than the Lighthouse CLS&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/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2eO9BsIb8Gx6kU4Zvbqa.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; PageSpeed Inights will show URL-level data where it exists, and attempt to fall back to origin-level data where this does not exist. Always check what data is showing to ensure you do not waste time trying to track down a CLS issue that actually exists on other pages on your origin! In the above example you can see this is URL-level data as shown in the top right of the image. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;identifying-load-cls-issues&quot;&gt;Identifying load CLS issues &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#identifying-load-cls-issues&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the CrUX and Lighthouse CLS scores of PageSpeed Insights are broadly in line, this usually indicates there is a load CLS issue that was detected by Lighthouse. In this case Lighthouse will help with two audits to provide more information on images causing CLS due to missing width and height, and also list all the elements that shifted for the page load along with their CLS contribution. You can see these audits by filtering on the CLS audits:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse Screenshot showing the CLS audits providing more information to help you identify and address CLS issues&quot; decoding=&quot;async&quot; height=&quot;544&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/2C3v6dGwPx2yFyYpVdue.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Lighthouse will identify the elements that were shifted, but often these are the ones &lt;em&gt;impacted&lt;/em&gt; rather than the elements &lt;em&gt;causing&lt;/em&gt; the CLS. For example, if a new element is inserted into the DOM, the elements that are beneath it will show in this audit, but the root cause is the addition of the new element above. However, the shifted element should be sufficient to help you identify and resolve the root cause. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/evaluate-performance/&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt; in DevTools also highlights layout shifts in the &lt;strong&gt;Experience&lt;/strong&gt; section. The &lt;strong&gt;Summary&lt;/strong&gt; view for a &lt;code&gt;Layout Shift&lt;/code&gt; record includes the cumulative layout shift score as well as a rectangle overlay showing the affected regions. This is particularly helpful to get more detail on load CLS issues since this is easily replicated with a reload performance profile.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Layout Shift records being displayed in the Chrome DevTools performance panel when expanding the Experience section&quot; decoding=&quot;async&quot; height=&quot;438&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ApDKifKCRNGWI2SXSR1g.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;After recording a new trace in the Performance panel, the &lt;b&gt;Experience&lt;/b&gt; section of the results is populated with a red-tinted bar displaying a &lt;code&gt;Layout Shift&lt;/code&gt; record. Clicking the record allows you to drill down into impacted elements (e.g. note the moved from/to entries).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;identifying-post-load-cls-issues&quot;&gt;Identifying post-load CLS issues &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#identifying-post-load-cls-issues&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the CrUX and Lighthouse CLS scores of PageSpeed Insights are not in line, then this likely indicates post-load CLS. Without field data helping to identify the reason (that we will cover next), these can be more tricky to track down.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot; rel=&quot;noopener&quot;&gt;Web Vitals Chrome extension&lt;/a&gt; can be used to monitor CLS as you interact with a page, either in a heads up display, or in the console—where you can &lt;a href=&quot;https://web.dev/debug-cwvs-with-web-vitals-extension/#cls-debug-information&quot;&gt;get more details above the elements shifted&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As an alternative to using the extension, you can browse your web page while &lt;a href=&quot;https://web.dev/cls/#measure-layout-shifts-in-javascript&quot;&gt;recording layout shifts using a Performance Observer&lt;/a&gt; pasted into the console.&lt;/p&gt;
&lt;p&gt;Once you are monitoring shifts you can try to replicate any post-load CLS issues. Scolling down a page is a common place for CLS to occur if content is lazy loaded and does not have space reserved for it. Content shifting on hover is another common post-load CLS cause. Both of these &amp;quot;interactions&amp;quot; are ineligible for the 500 milliseconds grace period as CLS during these periods are seen as being &amp;quot;unexpected shifts&amp;quot;, despite the user interaction, as they should not cause content to shift. Other interactions—such as clicks or taps—do have that grace period, but a common reason for CLS in these cases is taking longer than that 500 milliseconds to move or add content.&lt;/p&gt;
&lt;p&gt;We have a more detailed posted on &lt;a href=&quot;https://web.dev/debug-layout-shifts/&quot;&gt;debugging layout shifts&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;Once you have identified any common causes of CLS, the &lt;a href=&quot;https://web.dev/optimize-cls/lighthouse-user-flows/#timespans&quot;&gt;timespans user flow mode of Lighthouse&lt;/a&gt; can also be used to ensure typical user flows do not regress by introducing layout shifts.&lt;/p&gt;
&lt;h3 id=&quot;measuring-cls-elements-in-the-field&quot;&gt;Measuring CLS elements in the field &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#measuring-cls-elements-in-the-field&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is also recommended to monitor CLS in the field. This can be used to measure both the CLS and—perhaps more importantly—the elements impacting your CLS score in the field and feed them back to your analytics service.&lt;/p&gt;
&lt;p&gt;This can be invaluable in pointing you in the right direction of where the issue is as it can remove much of the guess work discribed above when you are trying to understand under what circumstances CLS is occuring. Again, be aware that this will measure the elements that shifted, rather than the root causes of those shifts, but this is often sufficient to identify the cause or at least to narrow down the problem.&lt;/p&gt;
&lt;p&gt;Measuring CLS in the field can also be used to rank the issues in order of importance based on most frequently experienced issues.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/GoogleChrome/web-vitals#send-attribution-data&quot; rel=&quot;noopener&quot;&gt;attribution functionality of the &lt;code&gt;web-vitals&lt;/code&gt; library&lt;/a&gt; allows this additional information to be collected. Read our &lt;a href=&quot;https://web.dev/debug-performance-in-the-field/&quot;&gt;Debug performance in the field&lt;/a&gt; post for more information on how to do this. Other RUM providers have also started collecting and presenting this data similarly.&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; RUM solutions that measure CLS in the field, including the &lt;code&gt;web-vitals&lt;/code&gt; library, may show differences that CrUX data as explained in the &lt;a href=&quot;https://web.dev/optimize-cls/crux-and-rum-differences/&quot;&gt;Why is CrUX data different from my RUM data?&lt;/a&gt; post. In particular, CLS that happens in iframes is not measurable from Web APIs but is visible to the user, and is therefore included in CrUX. So while field data can be invaluable for identifying CLS issues, be aware that it may be incomplete in certain scenarios. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;common-causes-of-cls&quot;&gt;Common causes of CLS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#common-causes-of-cls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you have identified the causes of CLS, you can start working on fixing the issues. In this section we will show some of the more common reasons for CLS, and what you can do to avoid them.&lt;/p&gt;
&lt;h3 id=&quot;images-without-dimensions&quot;&gt;Images without dimensions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#images-without-dimensions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Always include &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; size attributes on your images and video elements. Alternatively, reserve the required space with &lt;a href=&quot;https://web.dev/aspect-ratio/&quot;&gt;CSS &lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/a&gt; or similar. This approach ensures that the browser can allocate the correct amount of space in the document while the image is loading.&lt;/p&gt;
  &lt;figure&gt;
    &lt;video controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; poster=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/8wKRITUkK3Zrp5jvQ1Xw.jpg?auto=format&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/10TEOBGBqZm1SEXE7KiC.webm&quot; type=&quot;video/webm&quot; /&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/WOQn6K6OQcoElRw0NCkZ.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
   &lt;figcaption&gt;
      Images without width and height specified.
    &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure&gt;
    &lt;video controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; poster=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wm4VqJtKvove6qjiIjic.jpg?auto=format&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/38UiHViz44OWqlKFe1VC.webm&quot; type=&quot;video/webm&quot; /&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/sFxDb36aEMvTPIyZHz1O.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
   &lt;figcaption&gt;
      Images with width and height specified.
    &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse report showing the before/after impact to Cumulative Layout Shift after setting dimensions on images&quot; decoding=&quot;async&quot; height=&quot;148&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/A2OyrzSXuW1qYGWAarGx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Lighthouse 6.0 impact of setting image dimensions on CLS.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;history-of-width-and-height-attributes-on-images&quot;&gt;History of &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes on images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#history-of-width-and-height-attributes-on-images&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In the early days of the web, developers would add &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes to their &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags to ensure sufficient space was allocated on the page before the browser started fetching images. This would minimize reflow and re-layout.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;640&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;360&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;Puppy with balloons&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;You may notice &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; above do not include units. These &amp;quot;pixel&amp;quot; dimensions would ensure a 640x360 area would be reserved. The image would stretch to fit this space, regardless of whether the true dimensions matched or not.&lt;/p&gt;
&lt;p&gt;When &lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot; rel=&quot;noopener&quot;&gt;Responsive Web Design&lt;/a&gt; was introduced, developers began to omit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; and started using CSS to resize images instead:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* or max-width: 100%; */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A downside to this approach is space could only be allocated for an image once it began to download and the browser could determine its dimensions. As images loaded in, the page would reflow as each image appeared on screen. It became common for text to suddenly pop down the screen. This wasn&#39;t a great user experience at all.&lt;/p&gt;
&lt;p&gt;This is where aspect ratio comes in. The aspect ratio of an image is the ratio of its width to its height. It&#39;s common to see this expressed as two numbers separated by a colon (for example 16:9 or 4:3). For an x:y aspect ratio, the image is x units wide and y units high.&lt;/p&gt;
&lt;p&gt;This means if we know one of the dimensions, the other can be determined. For a 16:9 aspect ratio:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If puppy.jpg has a 360px height, width is 360 x (16 / 9) = 640px&lt;/li&gt;
&lt;li&gt;If puppy.jpg has a 640px width, height is 640 x (9 / 16) = 360px&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Knowing the aspect ratio allows the browser to calculate and reserve sufficient space for the height and associated area.&lt;/p&gt;
&lt;h4 id=&quot;modern-best-practice-for-setting-image-dimensions&quot;&gt;Modern best practice for setting image dimensions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#modern-best-practice-for-setting-image-dimensions&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Modern browsers now set the default aspect ratio of images based on an image&#39;s &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes so developers just need to set these, and include the above CSS, to prevent layout shifts:&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 comment&quot;&gt;&amp;lt;!-- set a 640:360 i.e a 16:9 aspect ratio --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;640&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;360&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;Puppy with balloons&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;All browsers will then add a &lt;a href=&quot;https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images&quot; rel=&quot;noopener&quot;&gt;default aspect ratio&lt;/a&gt; based on the element&#39;s existing &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes.&lt;/p&gt;
&lt;p&gt;This calculates an aspect ratio based on the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes before the image has loaded. It provides this information at the very start of layout calculation. As soon as an image is told to be a certain width (for example &lt;code&gt;width: 100%&lt;/code&gt;), the aspect ratio is used to calculate the height.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;aspect-ratio&lt;/code&gt; value is calculated by major browsers as the HTML is processed, rather than with a default User Agent stylesheet (see &lt;a href=&quot;https://jakearchibald.com/2022/img-aspect-ratio/#width--height-presentational-hints&quot; rel=&quot;noopener&quot;&gt;this post for a deep dive into why&lt;/a&gt;), so the value is displayed a little differently. For example, Chrome displays it like this in the Styles section of the Element panel:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;img[Attributes Style]&lt;/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; auto 640 / 360&lt;span class=&quot;token punctuation&quot;&gt;;&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;Safari behaves similarly by using a &lt;code&gt;HTML Attributes&lt;/code&gt; style source. Firefox does not currently display this calculated &lt;code&gt;aspect-ratio&lt;/code&gt; at all in it&#39;s Inspector panel, but does use it for layout.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;auto&lt;/code&gt; part of the above code is important as it causes the &lt;code&gt;640 / 360&lt;/code&gt; to be overriden with the image dimensions once the image is downloaded. If the image dimensions are different this will still cause some layout shift after the image loads, but this ensures the image aspect ratio is still used ultimately when it becomes available—as it was in the past—in case the HTML is incorrect. Plus, the shift is likely to be a lot smaller than the 0x0 default image size when dimensions are not provided!&lt;/p&gt;
&lt;p&gt;Tip: If you&#39;re having a hard time understanding aspect ratio, a handy &lt;a href=&quot;https://aspectratiocalculator.com/16-9.html&quot; rel=&quot;noopener&quot;&gt;calculator&lt;/a&gt; is available to help.&lt;/p&gt;
&lt;p&gt;For a fantastic deep-dive into aspect ratio with further thinking around responsive images, see &lt;a href=&quot;https://blog.logrocket.com/jank-free-page-loading-with-media-aspect-ratios/&quot; rel=&quot;noopener&quot;&gt;jank-free page loading with media aspect ratios&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your image is in a container, you can use CSS to resize the image to the width of this container. We set &lt;code&gt;height: auto;&lt;/code&gt; to avoid the image height being a fixed value (for example &lt;code&gt;360px&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;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;what-about-responsive-images&quot;&gt;What about responsive images? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#what-about-responsive-images&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When working with &lt;a href=&quot;https://web.dev/serve-responsive-images&quot;&gt;responsive images&lt;/a&gt;, &lt;code&gt;srcset&lt;/code&gt; defines the images you allow the browser to select between and what size each image is. To ensure &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; width and height attributes can be set, each image should use the same aspect ratio.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;&lt;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;1000&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;1000&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-1000.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w&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;Puppy with balloons&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What about &lt;a href=&quot;https://developer.mozilla.org/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#Art_direction&quot; rel=&quot;noopener&quot;&gt;art direction&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Pages may wish to include a cropped shot of an image on narrow viewports with the full image displayed on desktop.&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;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;(max-width: 799px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-480w-cropped.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-800w.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-800w.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Puppy with balloons&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It&#39;s very possible these images could have different aspect ratios. Chrome, Firefox, and Safari now support setting &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; on the &lt;code&gt;source&lt;/code&gt; children of the &lt;code&gt;picture&lt;/code&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;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 799px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-480w-cropped.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;480&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;400/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-800w.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;800&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;400/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;puppy-800w.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Puppy with balloons&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;800&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;400/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;h3 id=&quot;ads,-embeds,-and-other-late-loaded-content&quot;&gt;Ads, embeds, and other late-loaded content &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#ads,-embeds,-and-other-late-loaded-content&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we have seen, images have special considerations. However, images are not the only type of content that can cause layout shifts. Ads, embeds, iframes, and other dynamically injected content can all cause content after these to shift down, increasing your CLS.&lt;/p&gt;
&lt;p&gt;Ads are one of the largest contributors to layout shifts on the web. Ad networks and publishers often support dynamic ad sizes. Ad sizes increase performance/revenue due to higher click rates and more ads competing in the auction. Unfortunately, this can lead to a suboptimal user experience due to ads pushing visible content you&#39;re viewing down the page.&lt;/p&gt;
&lt;p&gt;Embeddable widgets allow you to include portable web content in your page, such as videos from YouTube, maps from Google Maps, and social media posts. These widgets often aren&#39;t aware in advance just how large their contents will be. For example, in the case of a social media post, it might have an embedded image, video, multiple rows of text, or a number of other unpredictable factors. As a result, platforms offering embeds do not always reserve space for their widgets and so cause layout shifts when they finally load.&lt;/p&gt;
&lt;p&gt;The techniques for dealing with these are all similar. The major differences are how much control you have over the content that will be inserted. If this is inserted by a third-party like an ad partner, you may not know the exact size of content that will be inserted, nor be able to control any layout shifts happening within those embeds.&lt;/p&gt;
&lt;h4 id=&quot;statically-reserve-space-for-late-loading-content&quot;&gt;Statically reserve space for late-loading content &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#statically-reserve-space-for-late-loading-content&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When placing late-loading content in the content flow, layout shifts can be avoided by reserving the space for them in the initial layout.&lt;/p&gt;
&lt;p&gt;This can be as simple as adding a &lt;code&gt;min-height&lt;/code&gt; styling to reserve space or, for responsive content such as ads, using the new &lt;a href=&quot;https://web.dev/aspect-ratio/&quot;&gt;&lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/a&gt; CSS property in a similar manner to the way browsers automatically use this for images with dimensions provided.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Three mobile devices with just text content in the first device, this is shifted down in the second device, and reserving space with a placeholder as shown in the third device prevents the shift&quot; decoding=&quot;async&quot; height=&quot;600&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/ThcGvVp0RiiABpmnWz7u.svg&quot; width=&quot;1180&quot; /&gt;
  &lt;figcaption&gt;
    Reserving space for ads can prevent layout shifts
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You may need to account for subtle differences in ad or placeholder sizes across form factors using media queries.&lt;/p&gt;
&lt;p&gt;For content that may not have a fixed height—like ads—you may not be able to reserve the exact amount of space needed to eliminate the layout shift entirely. If a smaller ad is served, a publisher can style the (larger) container to avoid layout shifts, or choose the most likely size for the ad slot based on historical data. The downside to this approach is that it will increase the amount of blank space, so keep in mind the trade-off here.&lt;/p&gt;
&lt;p&gt;Alternatively, set the initial size to the smallest size that will be used, and accept some level of shift for larger content. Using &lt;code&gt;min-height&lt;/code&gt;, as suggested above, will allow the parent element to grow as necessary. This will not fully eliminate CLS, but will hopefully reduce the impact of it to a more managable level. The default size of an empty element is 0px which gives maximum CLS, so any size is better than that!&lt;/p&gt;
&lt;p&gt;Try to avoid collapsing the reserved space if, for example, there is no ad returned, by showing a placeholder. Removing the space set aside for elements can cause just as much CLS as inserting content!&lt;/p&gt;
&lt;h4 id=&quot;avoid-placing-late-loading-content-near-the-top-of-the-viewport&quot;&gt;Avoid placing late-loading content near the top of the viewport &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#avoid-placing-late-loading-content-near-the-top-of-the-viewport&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Dynamically injected content near the top of the viewport may cause a greater layout shift than those at the middle. This is because elements inserted at the top generally have more content lower down, meaning more elements move when the late-loading content causes a shift.&lt;/p&gt;
&lt;p&gt;Conversely, dynamically injected content near the middle of the viewport may not shift as many elements as the content above it is less likely to move, but will still cause some CLS. Even content injected at the bottom of the screen will cause CLS as the content it replace is moved off-screen.&lt;/p&gt;
&lt;p&gt;The ideal scenario is not to shift any other content so reserving the appropriate space is preferred. Where this is not possible, minimizing the shifts can at least reduce the impact—both to your users and your CLS scores.&lt;/p&gt;
&lt;h4 id=&quot;avoid-inserting-new-content-without-a-user-interaction&quot;&gt;Avoid inserting new content without a user interaction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#avoid-inserting-new-content-without-a-user-interaction&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You&#39;ve probably experienced layout shifts due to UI that pops-in at the top or bottom of the viewport when you&#39;re trying to load a site. Similar to ads, this often happens with banners and forms that shift the rest of the page&#39;s content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;Sign-up to our newsletter!&amp;quot; (whoa, slow down! we just met!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;Related content&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;Install our [iOS/Android] app&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;We&#39;re still taking orders&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;GDPR notice&amp;quot;&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; poster=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/PF9ulVHDQOvoWendb6ea.jpg?auto=format&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/LEicZ7zHqGFrXl67Olve.webm&quot; type=&quot;video/webm&quot; /&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/XFvOHc2OB8vUD9GbpL2w.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
 &lt;figcaption&gt;
    Dynamic content without space reserved.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need to display these types of UI affordances, reserve sufficient space in the viewport for it in advance (for example, using a placeholder or skeleton UI) so that when it loads, it does not cause content in the page to surprisingly shift around. Alternatively, ensure the element is not part of the document flow by overlaying the content where this makes sense. See the &lt;a href=&quot;https://web.dev/cookie-notice-best-practices/&quot;&gt;Best practices for cookie notices&lt;/a&gt; post for more recommendations on these types of components.&lt;/p&gt;
&lt;p&gt;In some cases adding content dynamically is an important part of user experience. For example, when loading more products to a list of items or when updating live feed content. There are several ways to avoid unexpected layout shifts in those cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replace the old content with the new content within a fixed size container or use a carousel and remove the old content after the transition. Remember to disable any links and controls until the transition has completed to prevent accidental clicks or taps while the new content is coming in.&lt;/li&gt;
&lt;li&gt;Have the user initiate the load of new content, so they are not surprised by the shift (for example with a &amp;quot;Load more&amp;quot; or &amp;quot;Refresh&amp;quot; button). It&#39;s recommended to prefetch the content before the user interaction so that it shows up immediately. As a reminder, &lt;a href=&quot;https://web.dev/optimize-cls/cls/#user-initiated-layout-shifts&quot;&gt;layout shifts that occur within 500 milliseconds&lt;/a&gt; of user input are not counted towards CLS.&lt;/li&gt;
&lt;li&gt;Seamlessly load the content offscreen and overlay a notice to the user that it&#39;s available (for example, with a &amp;quot;Scroll up&amp;quot; button).&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Examples of dynamic content loading without causing unexpected layout shifts from Twitter and the Chloé website&quot; decoding=&quot;async&quot; height=&quot;458&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/OcYv93SYnIg1kfTihK6xqRDebvB2/TjsYVkcDf03ZOVCcsizv.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Examples of dynamic content loading without causing unexpected layout shifts. Left: Live feed content loading on Twitter. Right: &quot;Load More&quot; example on Chloé website. Check out how the YNAP team &lt;a href=&quot;https://medium.com/ynap-tech/how-to-optimize-for-cls-when-having-to-load-more-content-3f60f0cf561c&quot;&gt;optimized for CLS when loading more content&lt;/a&gt;.
  &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; If content is likely to take more than 500 milliseconds—for example it requires a network fetch—then reserving the expected space within that 500 millisecond timeframe and taking the impact of any future shift up front allows you to ensure any shifts will not be included in the CLS score. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;animations&quot;&gt;Animations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#animations&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Changes to CSS property values can require the browser to react to these changes. A number of values trigger re-layout, paint, and composite such as &lt;code&gt;box-shadow&lt;/code&gt; and &lt;code&gt;box-sizing&lt;/code&gt;. Try to avoid animating these.&lt;/p&gt;
&lt;p&gt;A number of CSS properties can be changed in a much more performant manner. For example, &lt;code&gt;transform&lt;/code&gt; animations can be used to translate, scale, rotate, or skew without triggering a re-layout and so completely avoiding layout shifts.&lt;/p&gt;
&lt;p&gt;When animations are instead done by changing &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt; CSS properties instead of using &lt;code&gt;translate&lt;/code&gt;, layout shifts occur. This happens &lt;strong&gt;even when the element being moved is in it&#39;s own layer and so does not cause shifts to other elements&lt;/strong&gt;. Composited animations via &lt;code&gt;translate&lt;/code&gt; are exempt from CLS as they cannot impact other elements. There are also other considerable performance benefits of using non-composited animations since they do no cause re-layout and therefore are much less work for the browser.&lt;/p&gt;
&lt;p&gt;To learn more about what CSS properties trigger layout see &lt;a href=&quot;https://web.dev/animations-guide/&quot;&gt;High-performance animations&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;web-fonts&quot;&gt;Web fonts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#web-fonts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Downloading and rendering web fonts is typically handled in one of two ways before the web font is downloaded:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The fallback font is swapped with the web font (FOUT—flash of unstyled text)&lt;/li&gt;
&lt;li&gt;&amp;quot;Invisible&amp;quot; text is displayed using the fallback font until a web font is available and the text is made visible (FOIT—flash of invisible text)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is important to understand that &lt;strong&gt;both of these can cause layout shifts&lt;/strong&gt;. Even though the text is invisible, it is laid out using the fallback font. This means the text block using the font, and the surrounding content, shifts when the web font loads—in the exact same way as for the visible font for FOUT.&lt;/p&gt;
&lt;p&gt;The following tools can help you minimize this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;font-display: optional&lt;/code&gt; can avoid a re-layout as the web font is only used if it is available by the time of initial layout.&lt;/li&gt;
&lt;li&gt;Ensure the appropriate fallback font is used. For example, using &lt;code&gt;font-family: &amp;quot;Google Sans&amp;quot;, sans-serif;&lt;/code&gt; will ensure the browser&#39;s &lt;code&gt;sans-serif&lt;/code&gt; fallback font is used while &lt;code&gt;&amp;quot;Google Sans&amp;quot;&lt;/code&gt; is loaded. Not specifying a fallback font using just &lt;code&gt;font-family: &amp;quot;Google Sans&amp;quot;&lt;/code&gt; will mean the default font is used, which on Chrome is &amp;quot;Times&amp;quot;—a serif font which is a worse match than the default &lt;code&gt;sans-serif&lt;/code&gt; font.&lt;/li&gt;
&lt;li&gt;Minimize the size differences between the fallback font and the web font using the new &lt;code&gt;size-adjust&lt;/code&gt;, &lt;code&gt;ascent-override&lt;/code&gt;, &lt;code&gt;descent-override&lt;/code&gt;, and &lt;code&gt;line-gap-override&lt;/code&gt; APIs as detailed in the &lt;a href=&quot;https://developer.chrome.com/blog/font-fallbacks/&quot; rel=&quot;noopener&quot;&gt;Improved font fallbacks&lt;/a&gt; post.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://web.dev/optimize-webfont-loading/#the-font-loading-api&quot;&gt;Font Loading API&lt;/a&gt; can reduce the time it takes to get necessary fonts.&lt;/li&gt;
&lt;li&gt;Load critical web fonts as early as possible using &lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt;. A preloaded font will have a higher chance to meet the first paint, in which case there&#39;s no layout shifting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read &lt;a href=&quot;https://web.dev/font-best-practices/&quot;&gt;Best practices for fonts&lt;/a&gt; for other font best practices.&lt;/p&gt;
&lt;h2 id=&quot;reduce-cls-by-ensuring-pages-are-eligible-for-the-bfcache&quot;&gt;Reduce CLS by ensuring pages are eligible for the bfcache &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#reduce-cls-by-ensuring-pages-are-eligible-for-the-bfcache&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A highly effective technique for keeping CLS scores low is to ensure your web pages are eligible for the &lt;a href=&quot;https://web.dev/bfcache/&quot;&gt;back/forward cache&lt;/a&gt; (bfcache).&lt;/p&gt;
&lt;p&gt;The bfcache keeps pages in browsers memory for a short period after you navigate away so if you return to them, then they will be restored exactly as you left them. This means the fully loaded page is instantly available—without any shifts which may be normally seen during load due to any of the reasons above.&lt;/p&gt;
&lt;p&gt;While this does potentially still mean the initial page load encounters layout shifts, when a user goes back through pages they are not seeing the same layout shifts repeatedly. You should always aim to avoid the shifts even on the initial load, but where that is more tricky to resolve fully, you can at least reduce the impact by avoiding them on any bfcache navigations.&lt;/p&gt;
&lt;p&gt;Back and forward navigations are common on many sites. For example, returning to a contents page, or a category page, or search results.&lt;/p&gt;
&lt;p&gt;When this was rolled out to Chrome, we saw &lt;a href=&quot;https://twitter.com/anniesullie/status/1491399685961293828?s=20&amp;amp;t=Qj_nzSRZD0_c-HaAnfr98Q&quot; rel=&quot;noopener&quot;&gt;noticeable improvements in CLS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The bfcache is used by default by all browsers, but some sites are ineligible for the bfcache due to a variety of reasons. Read &lt;a href=&quot;https://web.dev/bfcache/&quot;&gt;the bfcache article&lt;/a&gt; for more details on how to test and identify any issues preventing bfcache usage to ensure you are making full use of this feature to help your overall CLS score for your site.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-cls/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a number of techniques to identify and improve CLS as detailed above. There are allowances built into Core Web Vitals, so even if you cannot eliminate CLS completely, using some of these techniques should allow you to reduce the impact. This will be better for your users and hopefully allow you to stay within those limits.&lt;/p&gt;
&lt;p&gt;That&#39;s it for this guide. We hope it helps keep your pages just a little less shifty :)&lt;/p&gt;
</content>
    <author>
      <name>Barry Pollard</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimize First Input Delay</title>
    <link href="https://web.dev/optimize-fid/"/>
    <updated>2020-05-05T00:00:00Z</updated>
    <id>https://web.dev/optimize-fid/</id>
    <content type="html" mode="escaped">&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; FID will be &lt;a href=&quot;https://web.dev/inp-cwv/&quot;&gt;replaced by Interaction to Next Paint (INP)&lt;/a&gt; as a Core Web Vital in March 2024. &lt;/div&gt;&lt;/aside&gt;
&lt;blockquote&gt;
  &lt;p&gt;
    I clicked but nothing happened! Why can&#39;t I interact with this page? 😢
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; (FCP) and &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful
Paint&lt;/a&gt; (LCP) are both metrics that measure the time it takes for content to
visually render (paint) on a page. Although important, paint times do not capture &lt;em&gt;load
responsiveness&lt;/em&gt;: or how quickly a page responds to user interaction.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt; (FID) is a &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt; metric that captures a user&#39;s
first impression of a site&#39;s interactivity and responsiveness. It measures the time from when a user
first interacts with a page to the time when the browser is actually able to respond to that
interaction. FID is a &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#in-the-field&quot;&gt;field metric&lt;/a&gt; and cannot be
simulated in a lab environment. &lt;strong&gt;A real user interaction&lt;/strong&gt; is required in order to measure the
response delay.&lt;/p&gt;
&lt;picture&gt;
  &lt;source srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/eXyvkqRHQZ5iG38Axh1Z.svg&quot; media=&quot;(min-width: 640px)&quot; /&gt;
  &lt;img alt=&quot;Good fid values are 2.5 seconds, poor values are greater than 4.0 seconds and anything in between needs improvement&quot; decoding=&quot;async&quot; height=&quot;96&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Se4TiXIdp8jtLJVScWed.svg&quot; width=&quot;384&quot; /&gt;
&lt;/picture&gt;
&lt;p&gt;To help predict FID in the &lt;a href=&quot;https://web.dev/how-to-measure-speed/#lab-data-vs-field-data&quot;&gt;lab&lt;/a&gt;, we
recommend &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time (TBT)&lt;/a&gt;. They measure different things, but
improvements in TBT usually correspond to improvements in FID.&lt;/p&gt;
&lt;p&gt;The main cause of a poor FID is &lt;strong&gt;heavy JavaScript execution&lt;/strong&gt;. Optimizing how JavaScript parses,
compiles, and executes on your web page will directly reduce FID.&lt;/p&gt;
&lt;h2 id=&quot;heavy-javascript-execution&quot;&gt;Heavy JavaScript execution &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#heavy-javascript-execution&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The browser cannot respond to most user input while it&#39;s executing JavaScript on the main thread. In other words, the
browser can&#39;t respond to user interactions while the main thread is busy. To improve this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#long-tasks&quot;&gt;Break up Long Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#optimize-interaction-readiness&quot;&gt;Optimize your page for interaction readiness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#use-a-web-worker&quot;&gt;Use a web worker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#reduce-javascript-execution&quot;&gt;Reduce JavaScript execution time&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;long-tasks&quot;&gt;Break up Long Tasks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;ve already attempted to reduce the amount of JavaScript that loads on a single page, it can
be useful to break down long-running code into &lt;strong&gt;smaller, asynchronous tasks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/custom-metrics/#long-tasks-api&quot;&gt;&lt;strong&gt;Long Tasks&lt;/strong&gt;&lt;/a&gt; are JavaScript execution periods where users may
find your UI unresponsive. Any piece of code that blocks the main thread for 50 ms or more can be
characterized as a Long Task. Long Tasks are a sign of
potential JavaScript bloat (loading and executing more than a user may need right now).
Splitting up long tasks can reduce input delay on your site.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Long Tasks in Chrome DevTools&quot; decoding=&quot;async&quot; height=&quot;132&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Chrome DevTools &lt;a href=&quot;https://developers.google.com/web/updates/2020/03/devtools#long-tasks&quot;&gt;visualizes Long Tasks&lt;/a&gt; in the Performance Panel&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;FID should improve noticeably as you adopt best practices like code-splitting and breaking up your
Long Tasks. While TBT is not a field metric, it&#39;s useful for checking progress towards ultimately
improving both Time To Interactive (TTI) and FID.&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; For more information, take a look at &lt;a href=&quot;https://web.dev/long-tasks-devtools/&quot;&gt;Are long JavaScript tasks delaying your Time to Interactive?&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;optimize-your-page-for-interaction-readiness&quot;&gt;Optimize your page for interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#optimize-your-page-for-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a number of common causes for poor FID and TBT scores in web apps that rely heavily on
JavaScript:&lt;/p&gt;
&lt;h3 id=&quot;first-party-script-execution-can-delay-interaction-readiness&quot;&gt;First-party script execution can delay interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#first-party-script-execution-can-delay-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript size bloat, heavy execution times and inefficient chunking can slow down how soon a
page can respond to user input and impact FID, TBT, and TTI. Progressive loading of code and
features can help spread this work out and improve interaction readiness.&lt;/li&gt;
&lt;li&gt;Server-side rendered apps may look like they&#39;re getting pixels painted on the screen
quickly, but beware of user interactions being blocked by large script executions (e.g.
re-hydration to wire up event listeners). This can take several hundred milliseconds, sometimes
even seconds, if route-based code splitting is being used. Consider shifting more logic
server-side or generating more content statically during build time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below are the TBT scores before and after optimizing first-party script loading for an
application. By moving costly script loading (and execution) for a non-essential component off the
critical path, users were able to interact with the page much sooner.&lt;/p&gt;
&lt;img alt=&quot;Improvements in TBT score in Lighthouse after optimizing the first-party script.&quot; decoding=&quot;async&quot; height=&quot;148&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;data-fetching-can-impact-many-aspects-of-interaction-readiness&quot;&gt;Data-fetching can impact many aspects of interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#data-fetching-can-impact-many-aspects-of-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Waiting on a waterfall of cascading fetches (e.g. JavaScript and data fetches for components) can
impact interaction latency. Aim to minimize a reliance on cascading data fetches.&lt;/li&gt;
&lt;li&gt;Large inline datastores can push out HTML parsing time and impact both paint and interaction
metrics. Aim to minimize how much data needs to be post-processed on the client-side.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;third-party-script-execution-can-delay-interaction-latency-too&quot;&gt;Third-party script execution can delay interaction latency too &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#third-party-script-execution-can-delay-interaction-latency-too&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Many sites include third-party tags and analytics which can keep the network busy and
make the main thread periodically unresponsive, impacting interaction latency. Explore
on-demand loading of third-party code (e.g. maybe don&#39;t load those below-the-fold ads until
they&#39;re scrolled closer to the viewport).&lt;/li&gt;
&lt;li&gt;In some cases, third-party scripts can pre-empt first-party ones in terms of priority and
bandwidth on the main thread, also delaying how soon a page is interaction-ready. Attempt to
prioritize loading what you believe offers the greatest value to users first.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-a-web-worker&quot;&gt;Use a web worker &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#use-a-web-worker&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A blocked main thread is one of the main causes of input delay. &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Worker&quot; rel=&quot;noopener&quot;&gt;Web
workers&lt;/a&gt; make it possible to run JavaScript
on a background thread. Moving non-UI operations to a separate worker thread can cut down main
thread blocking time and consequently improve FID.&lt;/p&gt;
&lt;p&gt;Consider using the following libraries to make it easier to use web workers on your site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink&quot; rel=&quot;noopener&quot;&gt;Comlink&lt;/a&gt;: A helper library that abstracts
&lt;code&gt;postMessage&lt;/code&gt; and makes it easier to use&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/WebReflection/workway&quot; rel=&quot;noopener&quot;&gt;Workway&lt;/a&gt;: A general purpose web worker exporter&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/workerize&quot; rel=&quot;noopener&quot;&gt;Workerize&lt;/a&gt;: Move a module into a web worker&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; To learn more about how web workers can execute code off the main thread, refer to &lt;a href=&quot;https://web.dev/off-main-thread/&quot;&gt;Use Web Workers to run JavaScript off the browser&#39;s main thread&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;reduce-javascript-execution&quot;&gt;Reduce JavaScript execution time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#reduce-javascript-execution&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Limiting the amount of JavaScript on your page reduces the amount of time that the browser needs to
spend executing JavaScript code. This speeds up how fast the browser can begin to respond to any
user interactions.&lt;/p&gt;
&lt;p&gt;To reduce the amount of JavaScript executed on your page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defer unused JavaScript&lt;/li&gt;
&lt;li&gt;Minimize unused polyfills&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;defer-unused-javascript&quot;&gt;Defer unused JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#defer-unused-javascript&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By default all JavaScript is render-blocking. When the browser encounters a script tag that links to
an external JavaScript file, it must pause what it&#39;s doing and download, parse, compile, and execute
that JavaScript. Therefore you should only load the code that&#39;s needed for the page or
responding to user input.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/coverage/&quot; rel=&quot;noopener&quot;&gt;Coverage&lt;/a&gt; tab in Chrome
DevTools can tell you how much JavaScript is not being used on your web page.&lt;/p&gt;
&lt;img alt=&quot;The Coverage tab.&quot; decoding=&quot;async&quot; height=&quot;559&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To cut down on unused JavaScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code-split your bundle into multiple chunks&lt;/li&gt;
&lt;li&gt;Defer any non-critical JavaScript, including third-party scripts, using &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Code-splitting&lt;/strong&gt; is the concept of splitting a single large JavaScript bundle into smaller chunks
that can be conditionally loaded (also known as lazy loading).
&lt;a href=&quot;https://caniuse.com/#feat=es6-module-dynamic-import&quot; rel=&quot;noopener&quot;&gt;Most newer browsers support dynamic import syntax&lt;/a&gt;,
which allows for module fetching on demand:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;module.js&#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;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;module&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;// Do something with the module.&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;Dynamically importing JavaScript on certain user interactions (such as changing a route or
displaying a modal) will make sure that code not used for the initial page load is only fetched when
needed.&lt;/p&gt;
&lt;p&gt;Aside from general browser support, dynamic import syntax can be used in many different build
systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use &lt;a href=&quot;https://webpack.js.org/guides/code-splitting/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;,
&lt;a href=&quot;https://medium.com/rollup/rollup-now-has-code-splitting-and-we-need-your-help-46defd901c82&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt;,
or &lt;a href=&quot;https://parceljs.org/code_splitting.html&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt; as a module bundler, take advantage of
their dynamic import support.&lt;/li&gt;
&lt;li&gt;Client-side frameworks, like
&lt;a href=&quot;https://reactjs.org/docs/code-splitting.html#reactlazy&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;,
&lt;a href=&quot;https://angular.io/guide/lazy-loading-ngmodules&quot; rel=&quot;noopener&quot;&gt;Angular&lt;/a&gt;, and
&lt;a href=&quot;https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components&quot; rel=&quot;noopener&quot;&gt;Vue&lt;/a&gt; provide
abstractions to make it easier to lazy-load at the component-level.&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; Take a look at &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;Reduce JavaScript payloads with code splitting&lt;/a&gt; to learn more about code-splitting. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Aside from code-splitting, always use &lt;a href=&quot;https://javascript.info/script-async-defer&quot; rel=&quot;noopener&quot;&gt;async or
defer&lt;/a&gt; for scripts that are not necessary for
critical-path or above-the-fold content.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&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;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Unless there is a specific reason not to, all third-party scripts should be loaded with either &lt;code&gt;defer&lt;/code&gt;
or &lt;code&gt;async&lt;/code&gt; by default.&lt;/p&gt;
&lt;h4 id=&quot;minimize-unused-polyfills&quot;&gt;Minimize unused polyfills &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#minimize-unused-polyfills&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you author your code using modern JavaScript syntax and reference modern browsers APIs, you will
need to transpile it and include polyfills in order for it to work in older browsers.&lt;/p&gt;
&lt;p&gt;One of the main performance concerns of including polyfills and transpiled code in your site is that
newer browsers shouldn&#39;t have to download it if they do not need it. To cut down on the JavaScript
size of your application, minimize unused polyfills as much as possible and restrict their usage to
environments where they&#39;re needed.&lt;/p&gt;
&lt;p&gt;To optimize polyfill usage on your site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you use &lt;a href=&quot;https://babeljs.io/docs/en/index.html&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; as a transpiler, use
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt;&lt;/a&gt; to only include the polyfills
needed for the browsers you plan on targeting. For Babel 7.9, enable the
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#bugfixes&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;bugfixes&lt;/code&gt;&lt;/a&gt; option to further cut down
on any unneeded polyfills&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the module/nomodule pattern to deliver two separate bundles (&lt;code&gt;@babel/preset-env&lt;/code&gt; also
supports this via &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#targetsesmodules&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;target.esmodules&lt;/code&gt;&lt;/a&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;modern.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nomodule&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;legacy.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Many newer ECMAScript features compiled with Babel are already supported in environments
that support JavaScript modules. So by doing this, you simplify the process of making sure that
only transpiled code is used for browsers that actually need it.&lt;/p&gt;
&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; The &lt;a href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/&quot;&gt;Serve modern code to modern browsers for faster page loads&lt;/a&gt; guide goes into more detail about this topic. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;developer-tools&quot;&gt;Developer tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#developer-tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A number of tools are available to measure and debug FID:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse 6.0&lt;/a&gt; does not include
support for FID since it is a field metric. However, &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking
Time&lt;/a&gt; (TBT) can be used as a proxy. Optimizations that improve TBT should
also improve FID in the field.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse 6.0.&quot; decoding=&quot;async&quot; height=&quot;309&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience Report&lt;/a&gt;
provides real-world FID values aggregated at the origin-level&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;With thanks to Philip Walton, Kayce Basques, Ilya Grigorik, and Annie Sullivan for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Shopping for speed on eBay.com</title>
    <link href="https://web.dev/shopping-for-speed-on-ebay/"/>
    <updated>2020-01-22T00:00:00Z</updated>
    <id>https://web.dev/shopping-for-speed-on-ebay/</id>
    <content type="html" mode="escaped">&lt;p&gt;Speed was a &lt;a href=&quot;https://tech.ebayinc.com/engineering/speed-by-a-thousand-cuts/&quot; rel=&quot;noopener&quot;&gt;company-wide initiative&lt;/a&gt; for eBay in 2019, with many teams determined to make the
site and apps as fast as possible for users. In fact, &lt;strong&gt;for every 100 milliseconds improvement in
search page loading time, eBay saw a 0.5% increase in &amp;quot;Add to Cart&amp;quot; count.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;stats&quot;&gt;
  &lt;div class=&quot;stats__item&quot;&gt;
    &lt;p class=&quot;stats__figure&quot;&gt;100&lt;sub&gt;ms&lt;/sub&gt;&lt;/p&gt;
    &lt;p&gt;Improvement in load time&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class=&quot;stats__item&quot;&gt;
    &lt;p class=&quot;stats__figure&quot;&gt;0.5&lt;sub&gt;%&lt;/sub&gt;&lt;/p&gt;
    &lt;p&gt;Increase in &quot;Add to Cart&quot; count&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Through the adoption of &lt;a href=&quot;https://web.dev/performance-budgets-101/&quot;&gt;Performance Budgets&lt;/a&gt; (derived
after doing a competitive study with the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience
Report&lt;/a&gt;) and a focus on key
&lt;a href=&quot;https://web.dev/user-centric-performance-metrics/&quot;&gt;user-centric performance metrics&lt;/a&gt;, eBay was able to make
significant improvements to site speed.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The optimization efforst led to a 10% improvement on the homepage, a 13% improvement on the search page, and 3% improvement on item pages.&quot; decoding=&quot;async&quot; height=&quot;186&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/JXQCBQRuezhMQhfQShXq.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    eBay&#39;s speed improvements.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;…and their Chrome User Experience Report data highlights these improvements, too.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshots of PageSpeed Insights view of Chrome User Experience Report data highlighting fast FCP of 70% and fast FID of 88% for eBay.com&quot; decoding=&quot;async&quot; height=&quot;237&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/YeJPjxdDBrdbgLxcbl7E.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Chrome User Experience Report data for &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; and &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt; for the eBay.com origin.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There&#39;s still more work ahead but here&#39;s eBay&#39;s learnings so far.&lt;/p&gt;
&lt;h2 id=&quot;web-performance-cuts&quot;&gt;Web Performance &amp;quot;cuts&amp;quot; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#web-performance-cuts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The improvements eBay made were possible due to the reduction or &amp;quot;cuts&amp;quot; (in the size and time) of
various entities that take part in a user&#39;s journey.  This post covers topics that are relevant to
the web developer community at large, rather than eBay-specific topics.&lt;/p&gt;
&lt;h2 id=&quot;reduce-payload-across-all-text-resources&quot;&gt;Reduce payload across all text resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#reduce-payload-across-all-text-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One way to make sites fast is to simply load less code. eBay reduced their text payloads by trimming
all the &lt;a href=&quot;https://web.dev/remove-unused-code/&quot;&gt;unused and unnecessary bytes&lt;/a&gt; of JavaScript, CSS,
HTML, and JSON responses served to users. Previously, with every new feature, eBay kept increasing
the payload of their responses, without cleaning up what was unused. This added up over time and
became a performance bottleneck. Teams usually procrastinated on this cleanup activity, but you&#39;d
be surprised by how much eBay saved.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the wasted bytes in the response payload.&lt;/p&gt;
&lt;h2 id=&quot;critical-path-optimization-for-above-the-fold-content&quot;&gt;Critical path optimization for above-the-fold content &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#critical-path-optimization-for-above-the-fold-content&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not every pixel on the screen is equally important. The content &lt;a href=&quot;https://www.optimizely.com/optimization-glossary/above-the-fold/&quot; rel=&quot;noopener&quot;&gt;above-the-fold&lt;/a&gt; is &lt;a href=&quot;https://web.dev/extract-critical-css/&quot;&gt;more
critical&lt;/a&gt; than something below-the-fold. iOS/Android/desktop and web apps
are aware of this, but what about services? eBay&#39;s service architecture has a layer called
&lt;a href=&quot;https://tech.ebayinc.com/engineering/experience-services-ebays-solution-to-multi-screen-application-development/&quot; rel=&quot;noopener&quot;&gt;Experience
Services&lt;/a&gt;,
which the frontends (platform-specific apps and web servers) talk to.
This layer is specifically designed to be view- or device-based, rather than entity-based like item,
user, or order. eBay then introduced the concept of the critical path for Experience Services.
When a request comes to these services, they work on getting the data for above-the-fold
content immediately, by calling other upstream services in parallel. Once data is ready, it is
instantly flushed.
The below-the-fold data is sent in a later chunk or lazy-loaded. The outcome: users get to see
above-the-fold content quicker.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the time spent by services to display relevant
content.&lt;/p&gt;
&lt;h2 id=&quot;image-optimizations&quot;&gt;Image optimizations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#image-optimizations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Images are &lt;a href=&quot;https://almanac.httparchive.org/en/2019/media&quot; rel=&quot;noopener&quot;&gt;one of the largest contributors to page
bloat&lt;/a&gt;. Even
small optimizations go a long way. eBay did two optimizations for images.&lt;/p&gt;
&lt;p&gt;First, eBay standardized on the &lt;a href=&quot;https://web.dev/serve-images-webp/&quot;&gt;WebP image format&lt;/a&gt; for search
results across all platforms, including iOS, Android, and &lt;a href=&quot;https://caniuse.com/#feat=webp&quot; rel=&quot;noopener&quot;&gt;supported browsers&lt;/a&gt;. The search
results page is the most image-heavy page at eBay, and they were already using WebP, but not in a
consistent pattern.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshots of the DevTools network panel filtered to show WebP image requests from eBay.com&quot; decoding=&quot;async&quot; height=&quot;506&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/wxY64wQbCvgdEuI8DlUY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    WebP images being served to supported browsers on eBay.com.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Second, though eBay&#39;s listing images are heavily optimized (in both size and format), the same rigor
did not apply for curated images (for example, the top module on the
&lt;a href=&quot;https://www.ebay.com/&quot; rel=&quot;noopener&quot;&gt;homepage&lt;/a&gt;). eBay has a lot of hand-curated images, which are uploaded
through various tools. Previously the optimizations were up to the uploader, but now eBay enforces
the rules within the tools, so all images uploaded will be optimized appropriately.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the wasted image bytes sent to users.&lt;/p&gt;
&lt;h2 id=&quot;predictive-prefetch-of-static-assets&quot;&gt;Predictive prefetch of static assets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#predictive-prefetch-of-static-assets&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A user session on eBay is not just one page. It is a flow. For example, the flow can be a navigation from the homepage to a search page to an item page. So why don&#39;t pages in the flow help each other? That is the idea of &lt;a href=&quot;https://web.dev/predictive-prefetching/&quot;&gt;predictive prefetch&lt;/a&gt;, where one page prefetches the static assets required for the next likely page.&lt;/p&gt;
&lt;p&gt;With predictive prefetch, when a user navigates to the predicted page, the assets are already in the browser cache. This is done for CSS and JavaScript assets, where the URLs can be retrieved ahead of time. One thing to note here is that it helps only on first-time navigations. On subsequent navigations, the static assets will already be in the cache.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;eBay is doing predictive prefetching of static assets. Home prefetches assets for Search, Search prefetches assets for Item, and so on. Machine-learning- and analytics-based prefetching is under consideration.&quot; decoding=&quot;async&quot; height=&quot;448&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dcipECBEv200bO8CWkrs.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the network time for CSS and JavaScript static assets on the first navigation.&lt;/p&gt;
&lt;h2 id=&quot;prefetching-top-search-results&quot;&gt;Prefetching top search results &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#prefetching-top-search-results&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a user searches eBay, eBay&#39;s analytics data suggests that it is highly likely that the user
will navigate to an item in the top 10 of the search results. So eBay now prefetches the
items from search and keeps them ready for when the user navigates. The prefetching happens at two levels.&lt;/p&gt;
&lt;p&gt;The first level happens server-side, where the item service caches the top 10 items in search results. When the user
goes to one of those items, eBay now saves server processing time. Server-side caching is leveraged by
platform-specific apps and is rolled out globally.&lt;/p&gt;
&lt;p&gt;The other level happens in the browser cache, which is available
in Australia. Item prefetch was an advanced optimization due to the dynamic nature of items. There
are also many nuances to it: page impressions, capacity, auction items, and so on. You can learn more
about it in &lt;a href=&quot;https://www.youtube.com/watch?v=ogEhUnQdQiU&amp;amp;t=984s&quot; rel=&quot;noopener&quot;&gt;LinkedIn&#39;s Performance Engineering Meetup
presentation&lt;/a&gt;, or stay tuned for a detailed blog
post on the topic from eBay&#39;s engineers.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;eBay prefetches the top 5 items in search result pages for fast subsequent loads. This happens during idle time with requestIdleCallback(). This resulted in a 759ms faster median above-the-fold time, a custom metric that is similar to First Meaningful Paint. eBay saw a positive impact on conversions from prefetching.&quot; decoding=&quot;async&quot; height=&quot;451&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/6wW7yHAD7vMBDUDCzm2B.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here can either be server processing time or network time,
depending on where the item is cached.&lt;/p&gt;
&lt;h2 id=&quot;eager-downloading-of-search-images&quot;&gt;Eager downloading of search images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#eager-downloading-of-search-images&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the search results page, when a query is issued at a high level, two things happen. One is the recall/ranking step, where the most relevant items matching the query are returned. The second step is augmenting the recalled items with additional user-context related information such as shipping costs.
eBay now immediately sends the first 10 item images to the browser in a chunk along with the header, so the downloads can start before the rest of the markup arrives. As a result, the images will now appear quicker. This change is rolled out globally for the web platform.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the download start time for search result images.&lt;/p&gt;
&lt;h2 id=&quot;edge-caching-for-autosuggestion-data&quot;&gt;Edge caching for autosuggestion data &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#edge-caching-for-autosuggestion-data&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When users type in letters in the search box, suggestions pop-up. These suggestions do not change for letter combinations for at least a day. They are ideal candidates to be cached and served from a &lt;a href=&quot;https://en.wikipedia.org/wiki/Content_delivery_network&quot; rel=&quot;noopener&quot;&gt;CDN&lt;/a&gt; (for a max of 24 hours), instead of requests going all the way to a data center. International markets especially benefit from CDN caching.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of eBay&amp;#x27;s search box displaying autocomplete suggestions for a search query.&quot; decoding=&quot;async&quot; height=&quot;417&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5HVWuq5nIvQ6aCoaltIl.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;There was a catch, though. eBay had some elements of personalization in the suggestions pop-up,
which can&#39;t be cached efficiently. Fortunately, it was not an issue in the platform-specific apps, as the user
interface for personalization and suggestions could be separated. For the web, in international
markets, latency was more important than the small benefit of personalization. With that out of the
way, eBay now has autosuggestions served from a CDN cache globally for platform-specific apps and non-US
markets for eBay.com.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is the network latency and server processing time for
autosuggestions.&lt;/p&gt;
&lt;h2 id=&quot;edge-caching-for-unrecognized-homepage-users&quot;&gt;Edge caching for unrecognized homepage users &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#edge-caching-for-unrecognized-homepage-users&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the web platform, the homepage content for unrecognized users is the same for a particular region. These are users who are either using eBay for the first time or starting a fresh session, hence no personalization. Though the homepage creatives keep changing frequently there is still room for caching.&lt;/p&gt;
&lt;p&gt;eBay decided to cache the unrecognized user content (HTML) on their edge network (&lt;a href=&quot;https://en.wikipedia.org/wiki/Point_of_presence&quot; rel=&quot;noopener&quot;&gt;PoPs&lt;/a&gt;) for a short period. First-time users can now get homepage content served from a server near them, instead of from a faraway data center. eBay is still experimenting with this in international markets, where it will have a bigger impact.&lt;/p&gt;
&lt;p&gt;The &amp;quot;cut&amp;quot; here is again both network latency and server processing time for unrecognized users.&lt;/p&gt;
&lt;h2 id=&quot;optimizations-for-other-platforms&quot;&gt;Optimizations for other platforms &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#optimizations-for-other-platforms&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;iosandroid-app-parsing-improvements&quot;&gt;iOS/Android app parsing improvements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#iosandroid-app-parsing-improvements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;iOS/Android apps talk to backend services whose response format is typically JSON. These JSON payloads can be large. Instead of parsing the whole JSON to render something on the screen, eBay introduced an efficient parsing algorithm that optimizes for content that needs to be displayed immediately.&lt;/p&gt;
&lt;p&gt;Users can now see the content quicker. In addition, for the Android app, eBay starts initializing the search view controllers as soon as the user starts typing in the search box (iOS already had this optimization). Previously this happened only after users pressed the search button. Now users can get to their search results faster. The &amp;quot;cut&amp;quot; here is the time spent by devices to display relevant content.&lt;/p&gt;
&lt;h3 id=&quot;android-app-startup-time-improvements&quot;&gt;Android app startup time improvements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#android-app-startup-time-improvements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This applies to &lt;a href=&quot;https://developer.android.com/topic/performance/vitals/launch-time#cold&quot; rel=&quot;noopener&quot;&gt;cold start&lt;/a&gt; time optimizations for Android apps. When an app is cold started, a lot of initialization happens both at the OS level and application level. Reducing the initialization time at the application level helps users see the home screen quicker. eBay did some profiling and noticed that not all initializations are required to display content and that some can be done lazily.&lt;/p&gt;
&lt;p&gt;More importantly, eBay observed that there was a blocking third-party analytics call that delayed the rendering on the screen. Removing the blocking call and making it async further helped cold start times. The &amp;quot;cut&amp;quot; here is the unnecessary startup time for Android apps.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/shopping-for-speed-on-ebay/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the performance &amp;quot;cuts&amp;quot; eBay made collectively contributed towards moving the needle, and it happened over a period of time. The releases were phased in throughout the year, with each release shaving off tens of milliseconds, ultimately reaching the point where eBay is now:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshots of Chrome UX Report showing field data improvements for eBay.com.&quot; decoding=&quot;async&quot; height=&quot;529&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/GxKfB8GHUd9cQWLb0Pkj.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    The impact of eBay&#39;s speed efforts on their field metrics over time, as illustrated by the &lt;a href=&quot;https://g.co/chromeuxdash&quot;&gt;Chrome UX Report Dashboard&lt;/a&gt;.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Performance is a feature and a &lt;a href=&quot;https://web.dev/value-of-speed/&quot;&gt;competitive advantage&lt;/a&gt;. Optimized experiences lead to higher user engagement, conversions, and ROI. In eBay&#39;s case, these optimizations varied from things that were low-effort to a few that were advanced.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://tech.ebayinc.com/engineering/speed-by-a-thousand-cuts/&quot; rel=&quot;noopener&quot;&gt;Speed by a thousand cuts&lt;/a&gt; to learn more and be on the lookout for more detailed articles by eBay engineers on their performance work in the near future.&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Accessibility tips for web developers</title>
    <link href="https://web.dev/a11y-tips-for-web-dev/"/>
    <updated>2019-12-06T00:00:00Z</updated>
    <id>https://web.dev/a11y-tips-for-web-dev/</id>
    <content type="html" mode="escaped">&lt;p&gt;It&#39;s awesome to build sites that are inclusive and accessible to everyone.
There are at least six key areas of disability you can optimize for:
&lt;strong&gt;visual&lt;/strong&gt;, &lt;strong&gt;hearing&lt;/strong&gt;, &lt;strong&gt;mobility&lt;/strong&gt;, &lt;strong&gt;cognition&lt;/strong&gt;, &lt;strong&gt;speech&lt;/strong&gt;, and &lt;strong&gt;neural&lt;/strong&gt;.
Many tools and resources can help here,
even if you&#39;re totally new to web accessibility.&lt;/p&gt;
&lt;p&gt;Over one billion people live with some form of disability.
You might have been in a loud room at some point
trying to hear the conversation around you
or in a low-lighting condition trying to find something in the dark.
Do you remember the frustration you felt with that circumstance?
Now imagine if that temporary condition were permanent.
How different would your experience on the web be?&lt;/p&gt;
&lt;p&gt;To be accessible, sites need to work across multiple devices
with varying screen sizes and different kinds of input, such as screen readers.
Moreover, sites should be usable by the broadest group of users,
including those with disabilities.
Here&#39;s a sample of just a few disabilities your users may have:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Vision&lt;/th&gt;
        &lt;th&gt;Hearing&lt;/th&gt;
        &lt;th&gt;Mobility&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Low vision&lt;/li&gt;
            &lt;li&gt;Blindness&lt;/li&gt;
            &lt;li&gt;Color blindness&lt;/li&gt;
            &lt;li&gt;Cataracts&lt;/li&gt;
            &lt;li&gt;Sun glare&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Hard of hearing&lt;/li&gt;
            &lt;li&gt;Deafness&lt;/li&gt;
            &lt;li&gt;Noise&lt;/li&gt;
            &lt;li&gt;Ear infection&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Spinal cord injury&lt;/li&gt;
            &lt;li&gt;Limited dexterity&lt;/li&gt;
            &lt;li&gt;Hands full&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;th&gt;Cognitive&lt;/th&gt;
        &lt;th&gt;Speech&lt;/th&gt;
        &lt;th&gt;Neural&lt;/th&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Learning disability&lt;/li&gt;
            &lt;li&gt;Sleepiness or distraction&lt;/li&gt;
            &lt;li&gt;Migraine&lt;/li&gt;
            &lt;li&gt;Autism&lt;/li&gt;
            &lt;li&gt;Seizure&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Ambient noise&lt;/li&gt;
            &lt;li&gt;Sore throat&lt;/li&gt;
            &lt;li&gt;Speech impediment&lt;/li&gt;
            &lt;li&gt;Unable to speak&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
          &lt;ul&gt;
            &lt;li&gt;Depression&lt;/li&gt;
            &lt;li&gt;PTSD&lt;/li&gt;
            &lt;li&gt;Bipolar disorder&lt;/li&gt;
            &lt;li&gt;Anxiety&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Visual issues&lt;/strong&gt; range from an inability to distinguish colors to no vision at all.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure text content meets a minimum
&lt;a href=&quot;http://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast&quot; rel=&quot;noopener&quot;&gt;contrast ratio threshold&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Avoid communicating information
&lt;a href=&quot;http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-without-color&quot; rel=&quot;noopener&quot;&gt;using solely color&lt;/a&gt;
and ensure that all text is
&lt;a href=&quot;http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-scale&quot; rel=&quot;noopener&quot;&gt;resizable&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ensure all user interface components can be used with assistive technologies
such as screen readers, magnifiers, and braille displays.
This entails ensuring that UI components are marked up
such that accessibility APIs can programmatically determine
the &lt;em&gt;role&lt;/em&gt;, &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;value&lt;/em&gt;, and &lt;em&gt;title&lt;/em&gt; of any element.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The element inspection feature in the Chrome, Edge, and Firefox developer
tools displays a tooltip of CSS properties
that includes a quick check for color contrast ratio.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of the Chrome DevTools Inspect Element tooltip.&quot; decoding=&quot;async&quot; height=&quot;370&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/avwZaOjEWT7pES1OqUly.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;I personally live with low vision, and I often find myself zooming in on sites,
their DevTools, and the terminal.
While supporting zoom is almost never at the top of developers&#39; to-do lists,
it can make a world of difference to users like me.🤓&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hearing issues&lt;/strong&gt; mean a user may have issues hearing sound emitted from a page.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provide
&lt;a href=&quot;http://www.w3.org/TR/WCAG20/#media-equiv-av-only-alt&quot; rel=&quot;noopener&quot;&gt;text alternatives&lt;/a&gt;
for all content that is not strictly text.&lt;/li&gt;
&lt;li&gt;Test that your UI components are still functional
&lt;a href=&quot;http://www.w3.org/TR/2008/REC-WCAG20-20081211/#content-structure-separation-understanding&quot; rel=&quot;noopener&quot;&gt;without sound&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Screenshot of the ChromeVox screen reader reading a web page.&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ZIbJHF5vyMxmKAN9juO1.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;strong&gt;Mobility issues&lt;/strong&gt; can include the inability to operate a mouse, a keyboard, or a touch screen.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make the content of your UI components
&lt;a href=&quot;http://www.w3.org/TR/wai-aria-practices/#keyboard&quot; rel=&quot;noopener&quot;&gt;functionally accessible from a keyboard&lt;/a&gt;
for any actions one would otherwise use a mouse for.&lt;/li&gt;
&lt;li&gt;Ensure pages are correctly marked up for assistive technologies—including
screen readers, voice control software, and physical switch controls—which
tend to use the same APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cognitive issues&lt;/strong&gt; mean a user may require assistive technologies
to help them with reading text, so it&#39;s important to ensure text alternatives exist.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Be mindful when using animations. Avoid video and animation that
&lt;a href=&quot;http://www.w3.org/TR/WCAG20/#time-limits&quot; rel=&quot;noopener&quot;&gt;repeat&lt;/a&gt;
or flash, which can cause &lt;a href=&quot;http://www.w3.org/TR/WCAG20/#seizure&quot; rel=&quot;noopener&quot;&gt;issues&lt;/a&gt;
for some users.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://web.dev/prefers-reduced-motion/#too-much-motion-in-real-life-and-on-the-web&quot;&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt;&lt;/a&gt;
CSS media query allows you to limit animations
and autoplaying videos for users who prefer reduced 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 comment&quot;&gt;/*&lt;br /&gt;If the user expresses a preference for reduced motion, don&#39;t use animations on buttons.&lt;br /&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; reduce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid interactions that are
&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/no-timing.html&quot; rel=&quot;noopener&quot;&gt;timing-based&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This may seem like a lot of bases to cover,
but we&#39;ll walk through the process for assessing
and then improving the accessibility of your UI components.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The GOV.UK accessibility team has made some great
&lt;a href=&quot;https://accessibility.blog.gov.uk/2016/09/02/dos-and-donts-on-designing-for-accessibility/&quot; rel=&quot;noopener&quot;&gt;accessibility dos and don&#39;ts digital posters&lt;/a&gt;
to spread awareness of best practices in your team:&lt;/p&gt;
&lt;img alt=&quot;Digital posters showing accessibility dos and don&amp;#x27;ts.&quot; decoding=&quot;async&quot; height=&quot;721&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/lmcS2dTmBHuUo3j0ERCp.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;are-your-ui-components-accessible&quot;&gt;Are your UI components accessible? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#are-your-ui-components-accessible&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When auditing your page&#39;s UI components for accessibility, ask yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can you use your UI component with the keyboard only?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Does the component manage focus and avoid focus traps?
Can it respond to the appropriate keyboard events?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can you use your UI component with a screen reader?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Have you provided text alternatives for any information presented visually?
Have you added semantic information using ARIA?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can your UI component work without sound?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Turn off your speakers and go through your use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can your UI component work without color?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ensure your UI component can be used by someone who cannot see colors.
A helpful tool for simulating color blindness is a Chrome extension called
&lt;a href=&quot;https://chrome.google.com/webstore/detail/see/dkihcccbkkakkbpikjmpnbamkgbjfdcn&quot; rel=&quot;noopener&quot;&gt;SEE&lt;/a&gt;.
(Try all four forms of color blindness simulation available.)
You may also be interested in the
&lt;a href=&quot;https://chrome.google.com/webstore/detail/daltonize/obcnmdgpjakcffkcjnonpdlainhphpgh&quot; rel=&quot;noopener&quot;&gt;Daltonize&lt;/a&gt;
extension, which is similarly useful.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can your UI component work with high-contrast mode enabled?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;All modern operating systems support a high contrast mode.
&lt;a href=&quot;https://chrome.google.com/webstore/detail/high-contrast/djcfdncoelnlbldjfhinnjlhdjlikmph?hl=en&quot; rel=&quot;noopener&quot;&gt;High Contrast&lt;/a&gt;
is a Chrome extension that can help here.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Standardized controls (such as &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;)
have accessibility built in by the browser.
They are focusable using the &lt;code&gt;Tab&lt;/code&gt; key;
they respond to keyboard events (like the &lt;code&gt;Enter&lt;/code&gt;, &lt;code&gt;Space&lt;/code&gt;, and arrow keys);
and they have semantic roles, states, and properties used by accessibility tools.
Their default styling should also meet the accessibility requirements listed above.&lt;/p&gt;
&lt;p&gt;Custom UI components
(with the exception of components that extend standard elements like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;)
do not have any built-in functionality, including accessibility,
so you need to provide it.
A good place to start when implementing accessibility
is to compare your component to an analogous standard element
(or a combination of several standard elements,
depending on how complex your component is).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Most browser developer tools support inspecting the accessibility tree of a page.
In Chrome DevTools, this is available via the &lt;strong&gt;Accessibility&lt;/strong&gt; tab in the &lt;strong&gt;Elements&lt;/strong&gt; panel:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of the accessibility tree view in Chrome DevTools.&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/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/FcpD3oNA1C39KbQuNinf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Firefox also has an &lt;strong&gt;Accessibility&lt;/strong&gt; panel:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of the accessibility tree view in FireFox DevTools.&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/DRqDC9mtfcejAIjLImdR.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Safari exposes accessibility information in the &lt;strong&gt;Elements&lt;/strong&gt; panel&#39;s &lt;strong&gt;Node&lt;/strong&gt; tab.&lt;/p&gt;
&lt;p&gt;The following is a list of questions you can ask yourself when attempting to make your UI components more accessible.&lt;/p&gt;
&lt;h2 id=&quot;can-your-ui-component-be-used-with-the-keyboard-alone&quot;&gt;Can your UI component be used with the keyboard alone? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#can-your-ui-component-be-used-with-the-keyboard-alone&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ideally, ensure that all functionality
in your UI component can be accessed via keyboard.
When designing your user experience,
think about how you would use your element with the keyboard alone
and figure out a consistent set of keyboard interactions.&lt;/p&gt;
&lt;p&gt;First, ensure that you have a sensible focus target for each component.
For example, a complex component like a menu may be one focus target within a page
but should then manage focus within itself so that the active menu item always takes focus.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of a menu and submenu that requires focus management.&quot; decoding=&quot;async&quot; height=&quot;377&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/8zpJMaaY0DuAHdugbSr3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Managing focus within a complex element.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;using-tabindex&quot;&gt;Using tabindex &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#using-tabindex&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;tabindex&lt;/code&gt; attribute allows elements and UI components to be focused using the keyboard. Keyboard-only and assistive technology users both need to be able to place keyboard focus on elements to interact with them. Built-in interactive elements (like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;) are implicitly focusable, so they don&#39;t need a &lt;code&gt;tabindex&lt;/code&gt; attribute unless you wish to change their position in the tab order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are three types of &lt;code&gt;tabindex&lt;/code&gt; values:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;tabindex=&amp;quot;0&amp;quot;&lt;/code&gt;&lt;/strong&gt; is the most common and places the element in the natural tab order (defined by the DOM order).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;a &lt;code&gt;tabindex&lt;/code&gt; value greater than 0&lt;/strong&gt; places the element in a manual tab order—all elements in the page with a positive &lt;code&gt;tabindex&lt;/code&gt; value are visited in numerical order before elements in the natural tab order.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;a &lt;code&gt;tabindex&lt;/code&gt; value equal to -1&lt;/strong&gt; causes the element to be programmatically focusable, but not in the tab order.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For custom UI components, always use &lt;code&gt;tabindex&lt;/code&gt; values of 0 or -1, as you won&#39;t be able to determine the order of elements on a given page ahead of time—and even if you did, the order may change. A &lt;code&gt;tabindex&lt;/code&gt; value of -1 is particularly useful for managing focus within complex components as described above.&lt;/p&gt;
&lt;p&gt;Also ensure that focus is always visible, whether by allowing the default focus ring style or by applying a discernible custom focus style. Remember not to trap keyboard users—they should be able to move focus away from an element using only the keyboard.&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; You may also be interested in the roving &lt;code&gt;tabindex&lt;/code&gt; or &lt;code&gt;aria-activedescendant&lt;/code&gt; approaches, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#Technique_1_Roving_tabindex&quot;&gt;covered over on MDN&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;using-autofocus&quot;&gt;Using autofocus &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#using-autofocus&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The HTML autofocus attribute allows an author to specify
that a particular element should automatically take focus
when the page is loaded.
&lt;code&gt;autofocus&lt;/code&gt; is already supported on
&lt;a href=&quot;https://html.spec.whatwg.org/multipage/forms.html#association-of-controls-and-forms&quot; rel=&quot;noopener&quot;&gt;all web form controls&lt;/a&gt;,
including buttons.
To autofocus elements in your own custom UI components,
call the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLElement.focus&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;focus()&lt;/code&gt;&lt;/a&gt; method,
supported on all HTML elements that can be focused
(for example, &lt;code&gt;document.querySelector(&#39;myButton&#39;).focus()&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;adding-keyboard-interaction&quot;&gt;Adding keyboard interaction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#adding-keyboard-interaction&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your UI component is focusable,
provide a good keyboard interaction story
when a component is focused by handling appropriate keyboard events.
For example, allow the user to use arrow keys to select menu options
and &lt;code&gt;Space&lt;/code&gt; or &lt;code&gt;Enter&lt;/code&gt; to activate buttons.
The ARIA &lt;a href=&quot;http://www.w3.org/TR/wai-aria-practices/#aria_ex&quot; rel=&quot;noopener&quot;&gt;design patterns guide&lt;/a&gt;
provides some guidance here.&lt;/p&gt;
&lt;p&gt;Finally, ensure that your keyboard shortcuts are discoverable.
A common practice is to have a keyboard shortcut legend (on-screen text)
to inform the user that shortcuts exist.
For example, &amp;quot;Press ? for keyboard shortcuts.&amp;quot;
Alternatively, a hint such a tooltip can be used
to inform the user about a shortcut.&lt;/p&gt;
&lt;p&gt;The importance of managing focus cannot be overstated.
One example is a navigation drawer.
If you add a UI component to the page,
you need to direct focus to an element inside of it;
otherwise, users may have to tab through the entire page to get there.
This can be a frustrating experience,
so be sure to test focus for all keyboard navigable components in your page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You can use &lt;a href=&quot;https://github.com/puppeteer/puppeteer&quot; rel=&quot;noopener&quot;&gt;Puppeteer&lt;/a&gt;
to automate running keyboard accessibility tests for toggling UI states.
&lt;a href=&quot;https://medium.com/walkme-engineering/web-accessibility-testing-d499a7f7a032&quot; rel=&quot;noopener&quot;&gt;WalkMe Engineering&lt;/a&gt;
has a great guide on this I recommend reading.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;WalkMe state toggle test.&quot; decoding=&quot;async&quot; height=&quot;400&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 441px) 441px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/3lZosaL1YXafLn4ZRINl.gif?auto=format&amp;w=882 882w&quot; width=&quot;441&quot; /&gt;
&lt;/figure&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Example for expanding and collapsing a category with the Space key&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; category &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$&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;.category&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// verify tabIndex, role and focus&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; elem&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 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;role&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;toEqual&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;button&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; elem&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 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;tabindex&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;toEqual&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;0&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// verify aria-expanded = false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; elem&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 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;aria-expanded&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;toEqual&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;false&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// toggle category by pressing Space&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keyboard&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;press&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Space&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// verify aria-expanded = true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; elem&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 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;aria-expanded&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;toEqual&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;true&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;can-you-use-your-ui-component-with-a-screen-reader&quot;&gt;Can you use your UI component with a screen reader? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#can-you-use-your-ui-component-with-a-screen-reader&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Around 1–2% of people use a screen reader.
Can you understand all important information
and interact with the component using the screen reader and keyboard alone?&lt;/p&gt;
&lt;p&gt;The following questions should help you address screen reader accessibility.&lt;/p&gt;
&lt;h3 id=&quot;do-all-components-and-images-have-meaningful-text-alternatives&quot;&gt;Do all components and images have meaningful text alternatives? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#do-all-components-and-images-have-meaningful-text-alternatives&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Wherever information about the &lt;em&gt;name&lt;/em&gt; or &lt;em&gt;purpose&lt;/em&gt;
of an interactive component is conveyed visually,
provide an accessible text alternative.&lt;/p&gt;
&lt;p&gt;For example, if your &lt;code&gt;&amp;lt;fancy-menu&amp;gt;&lt;/code&gt; UI component only displays a gear icon
to indicate that it&#39;s a settings menu,
it needs an accessible text alternative, such as &amp;quot;settings,&amp;quot;
that conveys the same information.
Depending on context,
you can provide a text alternative using an &lt;code&gt;alt&lt;/code&gt; attribute,
an &lt;code&gt;aria-label&lt;/code&gt; attribute, an &lt;code&gt;aria-labelledby&lt;/code&gt; attribute,
or plain text in the Shadow DOM.
You can find general technical tips in &lt;a href=&quot;http://webaim.org/resources/quickref/&quot; rel=&quot;noopener&quot;&gt;WebAIM Quick Reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any UI component that displays an image should provide a mechanism
for providing alternative text for that image, analogous to the &lt;code&gt;alt&lt;/code&gt; attribute.&lt;/p&gt;
&lt;h3 id=&quot;do-your-components-provide-semantic-information&quot;&gt;Do your components provide semantic information? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#do-your-components-provide-semantic-information&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Assistive technology conveys semantic information
that is otherwise expressed to sighted users via visual cues
such as formatting, cursor style, or position.
Standardized elements have this semantic information built-in by the browser,
but for custom components you need to use
&lt;a href=&quot;http://www.w3.org/WAI/PF/aria/&quot; rel=&quot;noopener&quot;&gt;ARIA&lt;/a&gt; to add the information.&lt;/p&gt;
&lt;p&gt;As a rule of thumb, any component that listens to a mouse click or hover event
should not only have some kind of keyboard event listener,
but also an ARIA role and potentially ARIA states and attributes.&lt;/p&gt;
&lt;p&gt;For example, a custom &lt;code&gt;&amp;lt;fancy-slider&amp;gt;&lt;/code&gt; UI component might take an ARIA role of slider,
which has some related ARIA attributes: &lt;code&gt;aria-valuenow&lt;/code&gt;, &lt;code&gt;aria-valuemin&lt;/code&gt; and &lt;code&gt;aria-valuemax&lt;/code&gt;.
By binding these attributes to the relevant properties on your custom component,
you can allow users of assistive technology to interact with the element,
change its value, and even cause the element&#39;s visual presentation to change accordingly.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of a slider.&quot; decoding=&quot;async&quot; height=&quot;56&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 159px) 159px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=159 159w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=181 181w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=207 207w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=236 236w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=269 269w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=306 306w, https://web-dev.imgix.net/image/admin/BD2bS6XEEUlORVOGHwhe.png?auto=format&amp;w=318 318w&quot; width=&quot;159&quot; /&gt;
  &lt;figcaption&gt;A range slider component.&lt;/figcaption&gt;
&lt;/figure&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;fancy-slider&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;slider&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-valuemin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-valuemax&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&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-valuenow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2.5&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;fancy-slider&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;can-users-understand-everything-without-relying-on-color&quot;&gt;Can users understand everything without relying on color? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#can-users-understand-everything-without-relying-on-color&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Color shouldn&#39;t be used as the only means of conveying information,
such as indicating a status, prompting the user for a response,
or visualizing data.
For example, if you have a pie chart,
provide labels and values for each slice
so users who have visual impairments can understand the information
even if they can&#39;t tell where the slices begin and end:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A pie chart with labels and values to ensure accessibility.&quot; decoding=&quot;async&quot; height=&quot;442&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 500px) 500px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/4DlbNfCX7AYYrPSpQg4L.png?auto=format&amp;w=1000 1000w&quot; width=&quot;500&quot; /&gt;
  &lt;figcaption&gt;An accessible pie chart. (From the &lt;a href=&quot;https://www.w3.org/WAI/GL/low-vision-a11y-tf/wiki/Informational_Graphic_Contrast_(Minimum)&quot; rel=&quot;noopener&quot;&gt;W3C Web Accessibility Initiative&lt;/a&gt;.)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;is-there-sufficient-contrast-between-text-and-images-and-their-background&quot;&gt;Is there sufficient contrast between text and images and their background? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#is-there-sufficient-contrast-between-text-and-images-and-their-background&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Any text content displayed in your component should meet the
&lt;a href=&quot;http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-contrast&quot; rel=&quot;noopener&quot;&gt;minimum WCAG AA-level contrast threshold&lt;/a&gt;.
Consider providing a high-contrast theme that meets the
&lt;a href=&quot;http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast7&quot; rel=&quot;noopener&quot;&gt;higher AAA threshold&lt;/a&gt;,
and ensure that user agent style sheets can be applied
if users require custom contrast or different colors.
You can use this &lt;a href=&quot;http://webaim.org/resources/contrastchecker/&quot; rel=&quot;noopener&quot;&gt;Color Contrast Checker&lt;/a&gt;
as an aid when designing your component.&lt;/p&gt;
&lt;h3 id=&quot;is-the-moving-or-flashing-content-in-your-components-stoppable-and-safe&quot;&gt;Is the moving or flashing content in your components stoppable and safe? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#is-the-moving-or-flashing-content-in-your-components-stoppable-and-safe&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Content that moves, scrolls, or blinks for more than five seconds
should be able to be paused, stopped or hidden.
In general, avoid flashing content.
If something must flash, make sure it flashes no more than three times per second.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-tooling&quot;&gt;Accessibility Tooling &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#accessibility-tooling&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A number of tools are available that can assist with
debugging the accessibility of your visual components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.deque.com/products/axe/&quot; rel=&quot;noopener&quot;&gt;Axe&lt;/a&gt; provides automated accessibility testing
for your framework or browser of choice.
&lt;a href=&quot;https://www.deque.com/blog/axe-and-attest-integration-puppeteer/&quot; rel=&quot;noopener&quot;&gt;Axe Puppeteer&lt;/a&gt;
can be used for writing automated accessibility tests.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;
Accessibility audits provide helpful insights for discovering common accessibility issues.
The accessibility score is a weighted average of all accessibility audits
based on &lt;a href=&quot;https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md&quot; rel=&quot;noopener&quot;&gt;Axe user impact assessments&lt;/a&gt;.
For monitoring accessibility via continuous integration, see &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; rel=&quot;noopener&quot;&gt;Lighthouse CI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Screenshot of the Lighthouse accessibility audit.&quot; decoding=&quot;async&quot; height=&quot;649&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Bft9DABqWge4ZRpF6wzK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://tenon.io/&quot; rel=&quot;noopener&quot;&gt;Tenon.io&lt;/a&gt; is useful for testing common accessibility problems.
Tenon has strong integration support across build tools, browsers (via extensions), and even text editors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are many library- and framework-specific tools
for highlighting accessibility issues with components.
For example, &lt;a href=&quot;https://web.dev/accessibility-auditing-react/&quot;&gt;web.dev&lt;/a&gt;
explains how to use &lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-jsx-a11y&quot; rel=&quot;noopener&quot;&gt;eslint-plugin-jsx-a11y&lt;/a&gt;
to highlight accessibility issues for React components in your editor:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a code editor with an accessibility issue flagged by eslint-plugin-jsx-a11y.&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/9bAOYq7Cr11vzf4P04d2.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;If you use Angular, &lt;a href=&quot;https://web.dev/accessible-angular-with-codelyzer&quot;&gt;codelyzer&lt;/a&gt;
provides in-editor accessibility audits too:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a code editor with an accessibility issue flagged by codelyzer.&quot; decoding=&quot;async&quot; height=&quot;433&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Ca3rCQlJ53C7ILx3hwot.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can examine the way that assistive technologies see web content by using
&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html#//apple_ref/doc/uid/TP40001078-CH210-SW1&quot; rel=&quot;noopener&quot;&gt;Accessibility Inspector&lt;/a&gt; (Mac)
or &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/dd373661(v=vs.85).aspx&quot; rel=&quot;noopener&quot;&gt;Windows Automation API Testing Tools&lt;/a&gt;
and &lt;a href=&quot;http://accessibility.linuxfoundation.org/a11yweb/util/accprobe/&quot; rel=&quot;noopener&quot;&gt;AccProbe&lt;/a&gt; (Windows).
You can also see the full accessibility tree that Chrome creates
by navigating to &lt;code&gt;about://accessibility&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The best way to test for screen reader support on a Mac is using the VoiceOver utility.
Use &lt;code&gt;⌘F5&lt;/code&gt; to enable or disable it, &lt;code&gt;Ctrl+Option ←→&lt;/code&gt; to move through the page,
and &lt;code&gt;Ctrl+Shift+Option + ↑↓&lt;/code&gt; to move up and down the accessibility tree.
For more detailed instructions,
see the &lt;a href=&quot;http://www.apple.com/voiceover/info/guide/_1131.html&quot; rel=&quot;noopener&quot;&gt;full list of VoiceOver commands&lt;/a&gt;
and the &lt;a href=&quot;http://www.apple.com/voiceover/info/guide/_1131.html#vo27972&quot; rel=&quot;noopener&quot;&gt;list of VoiceOver Web commands&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://khan.github.io/tota11y/&quot; rel=&quot;noopener&quot;&gt;tota11y&lt;/a&gt; is a useful visualizer
for assistive technology issues built by Khan Academy.
It&#39;s a script that adds a button to your document that triggers several plugins
for annotating things like insufficient contrast ratio and other a11y violations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On Windows, &lt;a href=&quot;http://www.nvaccess.org/&quot; rel=&quot;noopener&quot;&gt;NVDA&lt;/a&gt; is a free, open source screen reader
that&#39;s fully featured and rapidly gaining in popularity.
However, note that it has a much steeper learning curve for sighted users than VoiceOver.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://chromelens.xyz/&quot; rel=&quot;noopener&quot;&gt;ChromeLens&lt;/a&gt; helps develop for the visually impaired.
It also has great support for visualizing keyboard navigation paths.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of ChromeLens.&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/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/RcDZ95ALFvNeDdpdv2Mo.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.chromevox.com/&quot; rel=&quot;noopener&quot;&gt;ChromeVox&lt;/a&gt; is a screen reader available as a Chrome extension and built into ChromeOS devices.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/a11y-tips-for-web-dev/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We still have a long way to go to improve accessibility on the web.
Per the &lt;a href=&quot;https://almanac.httparchive.org/en/2019/accessibility&quot; rel=&quot;noopener&quot;&gt;Web Almanac&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4 out of every 5 sites have text that easily blends into the background, making it unreadable.&lt;/li&gt;
&lt;li&gt;49.91% of pages still fail to provide &lt;code&gt;alt&lt;/code&gt; attributes for some of their images.&lt;/li&gt;
&lt;li&gt;Only 24% of pages that use buttons or links include textual labels for them.&lt;/li&gt;
&lt;li&gt;Only 22.33% of pages provide labels for all their form inputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To learn more about accessibility fundamentals and help improve those statistics,
I recommend the &lt;a href=&quot;https://web.dev/accessible/&quot;&gt;Accessible to all&lt;/a&gt; docs on web.dev.
There&#39;s much we can do to build experiences that are more accessible for everyone.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of the web.dev &amp;#x27;Accessible to all&amp;#x27; collection page.&quot; decoding=&quot;async&quot; height=&quot;513&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/iMaXm08LsbVKpkNCZEwA.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Browser-level image lazy loading for the web</title>
    <link href="https://web.dev/browser-level-image-lazy-loading/"/>
    <updated>2019-08-06T00:00:00Z</updated>
    <id>https://web.dev/browser-level-image-lazy-loading/</id>
    <content type="html" mode="escaped">&lt;p&gt;Browser-level support for lazy loading images is now supported on the web! This video shows a &lt;a href=&quot;https://mathiasbynens.be/demo/img-loading-lazy&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; of the feature:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/native-lazy-loading/lazyload.webm&quot; type=&quot;video/webm&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/native-lazy-loading/lazyload.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;You can use the &lt;code&gt;loading&lt;/code&gt; attribute to lazy-load images without the need to write custom lazy loading code or use a separate JavaScript library. Let&#39;s dive into the details.&lt;/p&gt;
&lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#browser-compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 77, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      77
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 75, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      75
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 15.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      15.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/Performance/Lazy_loading#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Browsers that do not support the &lt;code&gt;loading&lt;/code&gt; attribute simply ignore it without side effects.&lt;/p&gt;
&lt;h2 id=&quot;why-browser-level-lazy-loading&quot;&gt;Why browser-level lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#why-browser-level-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://httparchive.org/reports/page-weight&quot; rel=&quot;noopener&quot;&gt;HTTP Archive&lt;/a&gt;, images are the most requested asset type for most websites and usually take up more bandwidth than any other resource. At the 90th percentile, sites send over 5 MB of images on desktop and mobile. That&#39;s a lot of &lt;a href=&quot;https://en.wikipedia.org/wiki/Cats_and_the_Internet&quot; rel=&quot;noopener&quot;&gt;cat pictures&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously, there were two ways to defer the loading of off-screen images:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using the &lt;a href=&quot;https://developer.chrome.com/blog/intersectionobserver/&quot; rel=&quot;noopener&quot;&gt;Intersection Observer API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;scroll&lt;/code&gt;, &lt;code&gt;resize&lt;/code&gt;, or &lt;code&gt;orientationchange&lt;/code&gt; &lt;a href=&quot;https://web.dev/lazy-loading-images/&quot;&gt;event handlers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either option can let developers include lazy loading functionality, and many developers have built third-party libraries to provide abstractions that are even easier to use. With lazy loading supported directly by the browser, however, there&#39;s no need for an external library. Browser-level lazymloading also ensures that deferred loading of images still works even if JavaScript is disabled on the client.&lt;/p&gt;
&lt;h2 id=&quot;the-loading-attribute&quot;&gt;The &lt;code&gt;loading&lt;/code&gt; attribute &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#the-loading-attribute&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chrome loads images at different priorities depending on where they&#39;re located with respect to the device viewport. Images below the viewport are loaded with a lower priority, but they&#39;re still fetched as the page loads.&lt;/p&gt;
&lt;p&gt;You can use the &lt;code&gt;loading&lt;/code&gt; attribute to completely defer the loading of offscreen images that are reached by scrolling:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&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;Here are the supported values for the &lt;code&gt;loading&lt;/code&gt; attribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lazy&lt;/code&gt;: Defer loading of the resource until it reaches a &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;calculated distance&lt;/a&gt; from the viewport.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager&lt;/code&gt;: Default loading behavior of the browser, which is the same as not including the attribute and means the image is loaded regardless of where it&#39;s located on the page. While this is the default, it can be useful to explicitly set this if your tooling automatically adds &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; if there is no explicit value, or if your linter complains if it is not explicitly set.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Images that are highly likely to be in-viewport, and in particular &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;LCP&lt;/a&gt; images, &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;should not be lazy-loaded&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;relationship-between-the-loading-attribute-and-fetch-priority&quot;&gt;Relationship between the &lt;code&gt;loading&lt;/code&gt; attribute and fetch priority &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#relationship-between-the-loading-attribute-and-fetch-priority&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;eager&lt;/code&gt; value is simply an instruction to load the image as usual, without delaying the load further if it is off-screen. It does not imply that the image is loaded any quicker than another image without the &lt;code&gt;loading=&amp;quot;eager&amp;quot;&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Browsers prioritize resources based on various heuristics, and the &lt;code&gt;loading&lt;/code&gt; attribute just states &lt;em&gt;when&lt;/em&gt; the image resource is queued, not &lt;em&gt;how&lt;/em&gt; it is prioritized in that queue. &lt;code&gt;eager&lt;/code&gt; just implies the usual eager queueing browsers use by default.&lt;/p&gt;
&lt;p&gt;If you want to increase the fetch priority of an important image (for example the LCP image), then &lt;a href=&quot;https://web.dev/fetch-priority/&quot;&gt;Fetch Priority&lt;/a&gt; should be used with &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that an image with &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; and &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; will still be delayed while it is off-screen, and then fetched with a high priority when it is nearly within the viewport. It would likely be fetched with a high priority in this case anyway, so this combination should not really be needed nor used.&lt;/p&gt;
&lt;h3 id=&quot;distance-from-viewport-thresholds&quot;&gt;Distance-from-viewport thresholds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All images that are above the fold—that is, immediately viewable without scrolling—load normally. Those that are far below the device viewport are only fetched when the user scrolls near them.&lt;/p&gt;
&lt;p&gt;Chromium&#39;s implementation of lazy loading tries to ensure that offscreen images are loaded early enough so that they have finished loading once the user scrolls near to them. By fetching nearby images well before they become visible in the viewport, we maximize the chance they are already loaded by the time they become visible.&lt;/p&gt;
&lt;p&gt;Compared to JavaScript lazy loading libraries, the thresholds for fetching images that scroll into view may be considered conservative.&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; Experiments conducted using Chrome on Android suggest that on 4G, 97.5% of below-the-fold images that are lazy-loaded were fully loaded within 10ms of becoming visible. Even on slow 2G networks, 92.6% of below-the-fold images were fully loaded within 10ms. This means browser-level lazy loading offers a stable experience regarding the visibility of elements that are scrolled into view. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The distance threshold is not fixed and varies depending on several factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The type of image resource being fetched&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://googlechrome.github.io/samples/network-information/&quot; rel=&quot;noopener&quot;&gt;effective connection type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the default values for the different effective connection types in the &lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/settings.json5;l=963-995&quot; rel=&quot;noopener&quot;&gt;Chromium source&lt;/a&gt;. These numbers, and even the approach of fetching only when a certain distance from the viewport is reached, may change in the future as the Chrome team improves heuristics to determine when to begin loading.&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; You can experiment with these different thresholds by &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/#throttle&quot;&gt;throttling the network&lt;/a&gt; in DevTools. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;improved-data-savings-and-distance-from-viewport-thresholds&quot;&gt;Improved data-savings and distance-from-viewport thresholds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#improved-data-savings-and-distance-from-viewport-thresholds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of July 2020, Chrome has made significant improvements to align the image lazy loading distance-from-viewport thresholds to better meet developer expectations.&lt;/p&gt;
&lt;p&gt;On fast connections (4G), we reduced Chrome&#39;s distance-from-viewport thresholds from &lt;code&gt;3000px&lt;/code&gt; to &lt;code&gt;1250px&lt;/code&gt; and on slower connections (3G or lower), changed the threshold from &lt;code&gt;4000px&lt;/code&gt; to &lt;code&gt;2500px&lt;/code&gt;. This change achieves two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img loading=lazy&amp;gt;&lt;/code&gt; behaves closer to the experience offered by JavaScript lazy loading libraries.&lt;/li&gt;
&lt;li&gt;The new distance-from-viewport thresholds still allow us to guarantee images have probably loaded by the time a user has scrolled to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find a comparison between the old vs. new distance-from-viewport thresholds for one of our demos on a fast connection (4G) below:&lt;/p&gt;
&lt;p&gt;Old thresholds. vs new thresholds:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The new and improved thresholds for image lazy loading, reducing the distance-from-viewport thresholds for fast connections from 3000px down to 1250px&quot; decoding=&quot;async&quot; height=&quot;460&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;and the new thresholds vs. LazySizes (a popular JS lazy loading library):&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The new  distance-from-viewport thresholds in Chrome loading 90KB of images compared to LazySizes loading in 70KB under the same network conditions&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;We are committed to working with the web standards community to explore better alignment in how distance-from-viewport thresholds are approached across different browsers.&lt;/p&gt;
&lt;h3 id=&quot;images-should-include-dimension-attributes&quot;&gt;Images should include dimension attributes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#images-should-include-dimension-attributes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While the browser loads an image, it does not immediately know the image&#39;s dimensions, unless these are explicitly specified. To enable the browser to reserve sufficient space on a page for images, it is recommended that all &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags include both &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes. Without dimensions specified, &lt;a href=&quot;https://web.dev/cls/&quot;&gt;layout shifts&lt;/a&gt; can occur, which are more noticeable on pages that take some time to load.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&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;Alternatively, specify their values directly in an inline style:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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 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;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The best practice of setting dimensions applies to &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags regardless of whether or not they are being loaded lazily. With lazy loading, this can become more relevant. Setting &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; on images in modern browsers also allows browsers to infer their intrinsic size.&lt;/p&gt;
&lt;p&gt;In most scenarios images still lazy-load if dimensions are not included, but there are a few edge cases you should be aware of. Without &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; specified, image dimensions are 0×0 pixels at first. If you have a gallery of such images, the browser may conclude that all of them fit inside the viewport at the start, as each takes up practically no space and no image is pushed offscreen. In this case the browser determines that all of them are visible to the user and decides to load everything.&lt;/p&gt;
&lt;p&gt;Also, &lt;a href=&quot;https://www.youtube.com/watch?v=4-d_SoCHeWE&quot; rel=&quot;noopener&quot;&gt;specifying image dimensions decreases the chances of layout shifts happening&lt;/a&gt;. If you are unable to include dimensions for your images, lazy loading them can be a trade-off between saving network resources and potentially being more at risk of layout shift.&lt;/p&gt;
&lt;p&gt;While lazy loading in Chromium is implemented in a way such that images are likely to be loaded once they are visible, there is still a small chance that they might not be loaded yet. In this case, missing &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes on such images increase their impact on Cumulative Layout Shift.&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; Take a look at this &lt;a href=&quot;https://mathiasbynens.be/demo/img-loading-lazy&quot;&gt;demo&lt;/a&gt; to see how the &lt;code&gt;loading&lt;/code&gt; attribute works with 100 pictures. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Images that are defined using the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element can also be lazy-loaded:&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;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;large.jpg 1x, larger.jpg 2x&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;photo.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;Although a browser will decide which image to load from any of the &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements, the &lt;code&gt;loading&lt;/code&gt; attribute only needs to be included to the fallback &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;h2 id=&quot;avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;Avoid lazy loading images that are in the first visible viewport &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You should avoid setting &lt;code&gt;loading=lazy&lt;/code&gt; for any images that are in the first visible viewport. This is particularly relevant for LCP images. See the article &lt;a href=&quot;https://web.dev/lcp-lazy-loading/&quot;&gt;The performance effects of too much lazy-loading&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;It is recommended to only add &lt;code&gt;loading=lazy&lt;/code&gt; to images which are positioned below the fold, if possible. Images that are eagerly loaded can be fetched right away, while images which are loaded lazily the browser currently needs to wait until it knows where the image is positioned on the page, which relies on the &lt;code&gt;IntersectionObserver&lt;/code&gt; to be available.&lt;/p&gt;
&lt;p&gt;Generally, any images within the viewport should be loaded eagerly using the browser&#39;s defaults. You do not need to specify &lt;code&gt;loading=eager&lt;/code&gt; for this to be the case for in-viewport images.&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 comment&quot;&gt;&amp;lt;!-- visible in the viewport --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-1.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-2.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-3.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&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 comment&quot;&gt;&amp;lt;!-- offscreen images --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-4.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-5.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;product-6.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;200&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;graceful-degradation&quot;&gt;Graceful degradation &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#graceful-degradation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Browsers that do not support the &lt;code&gt;loading&lt;/code&gt; attribute will ignore its presence. While these browsers will of course not get the benefits of lazy loading, including the attribute has no negative impact on them.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#faq&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;are-there-plans-to-automatically-lazy-load-images-in-chrome&quot;&gt;Are there plans to automatically lazy-load images in Chrome? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#are-there-plans-to-automatically-lazy-load-images-in-chrome&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Previously, Chromium automatically lazy-loaded any images that were well suited to being deferred if &lt;a href=&quot;https://blog.chromium.org/2019/04/data-saver-is-now-lite-mode.html&quot; rel=&quot;noopener&quot;&gt;Lite mode&lt;/a&gt; was enabled on Chrome for Android and the &lt;code&gt;loading&lt;/code&gt; attribute was either not provided or set as &lt;code&gt;loading=&amp;quot;auto&amp;quot;&lt;/code&gt;. However, &lt;a href=&quot;https://support.google.com/chrome/thread/151853370/sunsetting-chrome-lite-mode-in-m100-and-older?hl=en&quot; rel=&quot;noopener&quot;&gt;Lite mode has been deprecated&lt;/a&gt; (as was the non-standard &lt;code&gt;loading=&amp;quot;auto&amp;quot;&lt;/code&gt;) and there are currently no plans to provide automatically lazy-load of images in Chrome.&lt;/p&gt;
&lt;h3 id=&quot;can-i-change-how-close-an-image-needs-to-be-before-a-load-is-triggered&quot;&gt;Can I change how close an image needs to be before a load is triggered? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#can-i-change-how-close-an-image-needs-to-be-before-a-load-is-triggered&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These values are hardcoded and can&#39;t be changed through the API. However, they may change in the
future as browsers experiment with different threshold distances and variables.&lt;/p&gt;
&lt;h3 id=&quot;can-css-background-images-take-advantage-of-the-loading-attribute&quot;&gt;Can CSS background images take advantage of the &lt;code&gt;loading&lt;/code&gt; attribute? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#can-css-background-images-take-advantage-of-the-loading-attribute&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, it can currently only be used with &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;h3 id=&quot;is-there-a-downside-to-lazy-loading-images-that-are-within-the-device-viewport&quot;&gt;Is there a downside to lazy loading images that are within the device viewport? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#is-there-a-downside-to-lazy-loading-images-that-are-within-the-device-viewport&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is safer to avoid putting &lt;code&gt;loading=lazy&lt;/code&gt; on above-the-fold images, as Chrome won&#39;t preload &lt;code&gt;loading=lazy&lt;/code&gt; images in the &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;preload scanner&lt;/a&gt; and will also delay fetching such images until all layout is complete. See &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;Avoid lazy-loading images that are in the first visible viewport&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&quot;how-does-the-loading-attribute-work-with-images-that-are-in-the-viewport-but-not-immediately-visible-for-example-behind-a-carousel,-or-hidden-by-css-for-certain-screen-sizes&quot;&gt;How does the &lt;code&gt;loading&lt;/code&gt; attribute work with images that are in the viewport but not immediately visible (for example: behind a carousel, or hidden by CSS for certain screen sizes)? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-does-the-loading-attribute-work-with-images-that-are-in-the-viewport-but-not-immediately-visible-for-example-behind-a-carousel,-or-hidden-by-css-for-certain-screen-sizes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; &lt;em&gt;may&lt;/em&gt; prevent them being loaded when they are not visible but within the &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;calculated-distance&lt;/a&gt;. For example, Chrome, Safari and Firefox do not load images using &lt;code&gt;display: none;&lt;/code&gt; styling—either on the image element or on a parent element. However, other techniques to hide images—such as using &lt;code&gt;opacity:0&lt;/code&gt; styling—will still result in the images being loaded. Always test your implementation thoroughly to ensure it&#39;s acting as intended.&lt;/p&gt;
&lt;h3 id=&quot;what-if-im-already-using-a-third-party-library-or-a-script-to-lazy-load-images&quot;&gt;What if I&#39;m already using a third-party library or a script to lazy-load images? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#what-if-im-already-using-a-third-party-library-or-a-script-to-lazy-load-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With full support of native lazy loading now available in modern browsers, you may wish to reconsider if you still need a third-party library or script to lazy-load images.&lt;/p&gt;
&lt;p&gt;One reason to continue to use a third-party library along with &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; is to provide a polyfill for browsers that do not support the attribute, or to have more control over when lazy loading is triggered.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-handle-browsers-that-dont-support-lazy-loading&quot;&gt;How do I handle browsers that don&#39;t support lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-do-i-handle-browsers-that-dont-support-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a polyfill or use a third-party library to lazy-load images on your site. The &lt;code&gt;loading&lt;/code&gt;
property can be used to detect if the feature is supported in the browser:&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 string&quot;&gt;&#39;loading&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLImageElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// supported in browser&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// fetch polyfill/third-party library&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;For example, &lt;a href=&quot;https://github.com/aFarkas/lazysizes&quot; rel=&quot;noopener&quot;&gt;lazysizes&lt;/a&gt; is a popular JavaScript lazy loading library. You can detect support for the &lt;code&gt;loading&lt;/code&gt; attribute to load lazysizes as a fallback library only when &lt;code&gt;loading&lt;/code&gt; isn&#39;t supported. This works as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;&amp;lt;img src&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;img data-src&amp;gt;&lt;/code&gt; to avoid an eager load in unsupported browsers. If the &lt;code&gt;loading&lt;/code&gt; attribute is supported, swap &lt;code&gt;data-src&lt;/code&gt; for &lt;code&gt;src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;loading&lt;/code&gt; is not supported, load a fallback (lazysizes) and initiate it. As per lazysizes docs, you use the &lt;code&gt;lazyload&lt;/code&gt; class as a way to indicate to lazysizes which images to lazy-load.&lt;/li&gt;
&lt;/ul&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 comment&quot;&gt;&amp;lt;!-- Let&#39;s load this in-viewport image normally --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;hero.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Let&#39;s lazy-load the rest of these images --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token 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;data-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;unicorn.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;lazyload&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;data-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;cats.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;lazyload&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;data-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;dogs.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;lazyload&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;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;loading&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLImageElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; images &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;img[loading=&quot;lazy&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    images&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;img&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;      img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Dynamically import the LazySizes library&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &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;script&#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;    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&#39;https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here&#39;s a &lt;a href=&quot;https://lazy-loading.firebaseapp.com/lazy_loading_lib.html&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; of this pattern. Try it out in an older browser to see the fallback in action.&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 lazysizes library also provides a &lt;a href=&quot;https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/native-loading&quot;&gt;loading plugin&lt;/a&gt; that uses browser-level lazy loading when available but falls back to the library&#39;s custom functionality when needed. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;is-lazy-loading-for-iframes-also-supported-in-browsers&quot;&gt;Is lazy loading for iframes also supported in browsers? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#is-lazy-loading-for-iframes-also-supported-in-browsers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 77, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      77
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
79
&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
16.4
&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;iframe loading=lazy&amp;gt;&lt;/code&gt; has also been standardized and is already implemented in Chromium and Safari. This allows you to lazy-load iframes using the &lt;code&gt;loading&lt;/code&gt; attribute. See &lt;a href=&quot;https://web.dev/iframe-lazy-loading/&quot;&gt;this dedicated article about iframe lazy-loading&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&quot;how-does-browser-level-lazy-loading-affect-advertisements-on-a-web-page&quot;&gt;How does browser-level lazy loading affect advertisements on a web page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-does-browser-level-lazy-loading-affect-advertisements-on-a-web-page&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All ads displayed to the user in the form of an image or iframe lazy-load just like any other image or iframe.&lt;/p&gt;
&lt;h3 id=&quot;how-are-images-handled-when-a-web-page-is-printed&quot;&gt;How are images handled when a web page is printed? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-are-images-handled-when-a-web-page-is-printed&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All images and iframes are immediately loaded if the page is printed. See &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=875403&quot; rel=&quot;noopener&quot;&gt;issue #875403&lt;/a&gt; for details.&lt;/p&gt;
&lt;h3 id=&quot;does-lighthouse-recognize-browser-level-lazy-loading&quot;&gt;Does Lighthouse recognize browser-level lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#does-lighthouse-recognize-browser-level-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/lighthouse-whats-new-6.0/&quot;&gt;Lighthouse 6.0&lt;/a&gt; and above factor in approaches for offscreen image lazy loading that may use different thresholds, allowing them to pass the &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/offscreen-images/&quot; rel=&quot;noopener&quot;&gt;Defer offscreen images&lt;/a&gt; audit.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Baking in support for lazy loading images can make it significantly easier for you to improve the performance of your web pages.&lt;/p&gt;
&lt;p&gt;Are you noticing any unusual behavior with this feature enabled in Chrome? &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/entry?summary=%5BLazyLoad%5D:&amp;amp;comment=Application%20Version%20%28from%20%22Chrome%20Settings%20%3E%20About%20Chrome%22%29:%20%0DAndroid%20Build%20Number%20%28from%20%22Android%20Settings%20%3E%20About%20Phone/Tablet%22%29:%20%0DDevice:%20%0D%0DSteps%20to%20reproduce:%20%0D%0DObserved%20behavior:%20%0D%0DExpected%20behavior:%20%0D%0DFrequency:%20%0D%3Cnumber%20of%20times%20you%20were%20able%20to%20reproduce%3E%20%0D%0DAdditional%20comments:%20%0D&amp;amp;labels=Pri-2&amp;amp;components=Blink%3ELoader%3ELazyLoad%2C&quot; rel=&quot;noopener&quot;&gt;File a bug&lt;/a&gt;!&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Mathias Bynens</name>
    </author><author>
      <name>Barry Pollard</name>
    </author>
  </entry>
  
  <entry>
    <title>Are long JavaScript tasks delaying your Time to Interactive?</title>
    <link href="https://web.dev/long-tasks-devtools/"/>
    <updated>2019-05-29T00:00:00Z</updated>
    <id>https://web.dev/long-tasks-devtools/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;strong&gt;Long Tasks can keep the main thread busy, delaying user interaction. Chrome DevTools can now visualize Long Tasks, making it easier to see tasks to optimize.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you use Lighthouse to audit your pages, you may be familiar with &lt;a href=&quot;https://web.dev/tti/&quot;&gt;Time to Interactive&lt;/a&gt;, a metric representing when users can interact with your page and get a response. But did you know Long (JavaScript) Tasks can contribute heavily to a poor TTI?&lt;/p&gt;
&lt;img alt=&quot;Time to Interactive displayed in the Lighthouse Report&quot; decoding=&quot;async&quot; height=&quot;169&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/4XCzYI9gaUJDTTJu9JxH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;what-are-long-tasks&quot;&gt;What are Long Tasks? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/long-tasks-devtools/#what-are-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Long_Tasks_API&quot; rel=&quot;noopener&quot;&gt;Long Task&lt;/a&gt; is JavaScript code that monopolizes the main thread for extended periods of time, causing the UI to &amp;quot;freeze&amp;quot;.&lt;/p&gt;
&lt;p&gt;While a web page is loading, Long Tasks can tie up the main thread and make the page unresponsive to user input even if it looks ready. Clicks and taps often don&#39;t work because event listeners, click handlers etc have not yet been attached.&lt;/p&gt;
&lt;p&gt;CPU-heavy Long Tasks occur due to complex work that takes longer than 50ms. Why 50ms? &lt;a href=&quot;https://web.dev/rail/&quot;&gt;The RAIL model&lt;/a&gt; suggests you process user input events in &lt;a href=&quot;https://web.dev/rail/#response-process-events-in-under-50ms&quot;&gt;50ms&lt;/a&gt; to ensure a visible response within 100ms. If you don&#39;t, the connection between action and reaction is broken.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; While the RAIL model suggests providing a visual response to user input within 100 ms, the &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; metric&#39;s thresholds allow for up to 200 ms in order to set more easily achievable expectations, especially for slower devices. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;are-there-long-tasks-in-my-page-that-could-delay-interactivity&quot;&gt;Are there Long Tasks in my page that could delay interactivity? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/long-tasks-devtools/#are-there-long-tasks-in-my-page-that-could-delay-interactivity&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Until now, you&#39;ve needed to manually look for &amp;quot;long yellow blocks&amp;quot; of script over 50ms long in &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt; or use the &lt;a href=&quot;https://calendar.perfplanet.com/2017/tracking-cpu-with-long-tasks-api/&quot; rel=&quot;noopener&quot;&gt;Long Tasks API&lt;/a&gt; to figure out what tasks were delaying interactivity. This could be a little cumbersome.&lt;/p&gt;
&lt;img alt=&quot;A DevTools Performance panel screenshot showing the differences between short tasks and long tasks&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/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mSKnMWBcEBHWkXzTGCAH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To help ease your performance auditing workflow, &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-74/#longtasks&quot; rel=&quot;noopener&quot;&gt;DevTools now visualizes Long Tasks&lt;/a&gt;. Tasks (shown in gray) have red flags if they are Long Tasks.&lt;/p&gt;
&lt;img alt=&quot;DevTools visualizing Long Tasks as gray bars in the Performance Panel with a red flag for long tasks&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/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/fyDPyO4XbSINMVpSSY9E.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;Record a trace in the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/evaluate-performance/&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt; of loading up a web page.&lt;/li&gt;
&lt;li&gt;Look for a red flag in the main thread view. You should see tasks are now gray (&amp;quot;Task&amp;quot;).&lt;/li&gt;
&lt;li&gt;Hovering over a bar will let you know the duration of the task and if it was considered &amp;quot;long&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-causing-my-long-tasks&quot;&gt;What is causing my Long Tasks? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/long-tasks-devtools/#what-is-causing-my-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To discover what is causing a long task, select the gray &lt;strong&gt;Task&lt;/strong&gt; bar. In the drawer beneath, select &lt;strong&gt;Bottom-Up&lt;/strong&gt; and &lt;strong&gt;Group by Activity&lt;/strong&gt;. This allows you to see what activities contributed the most (in total) to the task taking so long to complete. Below, it appears to be a costly set of DOM queries.&lt;/p&gt;
&lt;img alt=&quot;Selecting a long task (labelled &amp;#x27;Task&amp;#x27;) in DevTools allows us to drill-down into the activities that were responsible for it.&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/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7irBiePkFJRmzKMlcJUV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;what-are-common-ways-to-optimize-long-tasks&quot;&gt;What are common ways to optimize Long Tasks? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/long-tasks-devtools/#what-are-common-ways-to-optimize-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Large scripts are often a major cause of Long Tasks so consider &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;splitting them up&lt;/a&gt;. Also keep an eye on third-party scripts; their Long Tasks can delay primary content from getting interactive.&lt;/p&gt;
&lt;p&gt;Break all your work into small chunks (that run in &amp;lt; 50ms) and run these chunks at the right place and time; the right place may even be off the main thread, in a worker. Phil Walton&#39;s &lt;a href=&quot;https://philipwalton.com/articles/idle-until-urgent/&quot; rel=&quot;noopener&quot;&gt;Idle Until Urgent&lt;/a&gt; is a good read on this topic. See also the &lt;a href=&quot;https://web.dev/optimize-long-tasks/&quot;&gt;optimize long tasks article&lt;/a&gt; for general strategies for managing and breaking up long tasks.&lt;/p&gt;
&lt;p&gt;Keep your pages responsive. Minimizing Long Tasks is a great way to ensure your users have a delightful experience when they visit your site. For more on Long Tasks, check out &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#tracking_long_tasks&quot; rel=&quot;noopener&quot;&gt;User-centric Performance Metrics&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Speed at scale: what&#39;s new in web performance?</title>
    <link href="https://web.dev/speed-at-scale/"/>
    <updated>2019-05-24T00:00:00Z</updated>
    <id>https://web.dev/speed-at-scale/</id>
    <content type="html" mode="escaped">&lt;p&gt;During the &lt;a href=&quot;https://www.youtube.com/watch?v=YJGCZCaIZkQ&amp;amp;feature=youtu.be&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Speed at Scale&amp;quot;
talk&lt;/a&gt; at Google
I/O 2019, we announced three things that we hope will improve web performance
over the coming year.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;YJGCZCaIZkQ&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;lighthouse-now-supports-performance-budgeting&quot;&gt;Lighthouse now supports Performance Budgeting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-at-scale/#lighthouse-now-supports-performance-budgeting&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/use-lighthouse-for-performance-budgets/&quot;&gt;LightWallet&lt;/a&gt;
is a new feature in Lighthouse that adds support for &lt;a href=&quot;https://web.dev/fast#set-performance-budgets&quot;&gt;performance
budgets&lt;/a&gt;. Performance budgets establish
standards for the performance of your site. More importantly, they make it is
easy to identify and fix performance regressions before they ship.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A LightWallet report showing which assets are over the file size budget.&quot; decoding=&quot;async&quot; height=&quot;607&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/b1hw1bMU0dCIqS45XdfW.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;LightWallet is available in the newest version of the Lighthouse CLI and only
takes a couple minutes to set up. These&lt;a href=&quot;https://web.dev/use-lighthouse-for-performance-budgets/&quot;&gt;
instructions&lt;/a&gt;
provide more information.&lt;/p&gt;
&lt;p&gt;Unsure what your budgets should be? Try our experimental &lt;a href=&quot;https://bit.ly/perf-budget-calculator&quot; rel=&quot;noopener&quot;&gt;Performance Budget
Calculator&lt;/a&gt; which can generate a
LightWallet compatible budget configuration.&lt;/p&gt;
&lt;h2 id=&quot;browser-level-image-and-iframe-lazy-loading-comes-to-the-web&quot;&gt;Browser-level image and iframe lazy loading comes to the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-at-scale/#browser-level-image-and-iframe-lazy-loading-comes-to-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web pages often contain a large number of images, which contribute to
data-usage, &lt;a href=&quot;https://httparchive.org/reports/state-of-images&quot; rel=&quot;noopener&quot;&gt;page-bloat&lt;/a&gt; and
slower page loads. Many of these images are offscreen, requiring a user to
scroll in order to view them.&lt;/p&gt;
&lt;p&gt;Until now, you&#39;ve needed to solve lazy loading images using a JavaScript
library but that may soon change. This summer, Chrome will be launching support
for the &lt;a href=&quot;https://addyosmani.com/blog/lazy-loading/&quot; rel=&quot;noopener&quot;&gt;loading&lt;/a&gt; attribute which
brings standardized &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; lazy loading to the web.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Browser-level lazy-loading highlighting offscreen content being loaded on-demand&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/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/5W51sHaRUB0NEuN0MaFh.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute allows a browser to defer loading offscreen images and
iframes until users scroll near them. &lt;code&gt;loading&lt;/code&gt; supports three values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lazy&lt;/code&gt;: is a good candidate for lazy loading.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager&lt;/code&gt;: is not a good candidate for lazy loading. Load right away.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;: browser will determine whether or not to lazily load.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;io2019.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&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;video-player.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&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;iframe&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 exact heuristics for &amp;quot;when the user scrolls near&amp;quot; is left up to the
browser. In general, our hope is that browsers will start fetching deferred
images and iframe content a little before it comes into the viewport.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute is implemented behind flags in Chrome Canary. You can
try out &lt;a href=&quot;https://mathiasbynens.be/demo/img-loading-lazy&quot; rel=&quot;noopener&quot;&gt;this demo&lt;/a&gt; in Chrome
75+ with the &lt;code&gt;about://flags/#enable-lazy-image-loading&lt;/code&gt; and
&lt;code&gt;about://flags/#enable-lazy-frame-loading&lt;/code&gt; flags turned on.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://addyosmani.com/blog/lazy-loading/&quot; rel=&quot;noopener&quot;&gt;write-up&lt;/a&gt; on the
lazy loading feature is available with more details.&lt;/p&gt;
&lt;h2 id=&quot;google-fonts-now-supports-font-display-as-a-query-parameter&quot;&gt;Google Fonts now supports font-display as a query parameter &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-at-scale/#google-fonts-now-supports-font-display-as-a-query-parameter&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We announced support for &lt;a href=&quot;https://font-display.glitch.me/&quot; rel=&quot;noopener&quot;&gt;font-display&lt;/a&gt; is now available in production for all &lt;a href=&quot;https://fonts.google.com/&quot; rel=&quot;noopener&quot;&gt;Google Fonts&lt;/a&gt; via the &lt;a href=&quot;https://developers.google.com/fonts/docs/getting_started#use_font-display&quot; rel=&quot;noopener&quot;&gt;display query-string parameter&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;https://fonts.googleapis.com/css?family=Lobster&amp;amp;display=swap&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;font-display&lt;/code&gt; descriptor lets you decide how your web fonts will render or
fallback, depending on how long it takes for them to load. It supports a number
of values including &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;block&lt;/code&gt;, &lt;code&gt;swap&lt;/code&gt;, &lt;code&gt;fallback&lt;/code&gt; and &lt;code&gt;optional&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Previously, the only way to specify &lt;code&gt;font-display&lt;/code&gt; for web fonts from Google Fonts was to self-host them but this change removes the need to do so.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developers.google.com/fonts/docs/getting_started#use_font-display&quot; rel=&quot;noopener&quot;&gt;Google Fonts
documentation&lt;/a&gt;
has been updated to include &lt;code&gt;font-display&lt;/code&gt; in the default code embeds (as seem
below). We hope this will encourage more developers to try out this exciting
addition.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Google Fonts embed code with font-display included in the URL as a query-parameter&quot; decoding=&quot;async&quot; height=&quot;528&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/aJqdPp1xobaYRDNx4aJd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Here&#39;s a &lt;a href=&quot;https://glitch.com/~truth-bookcase&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; on Glitch of using display
with multiple font families. Try it out with &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/#throttle&quot; rel=&quot;noopener&quot;&gt;DevTools network
emulation&lt;/a&gt;
to see the impact of &lt;code&gt;font-display: swap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;watch-for-more&quot;&gt;Watch for more &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-at-scale/#watch-for-more&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our talk also covered several production case studies of using advanced
performance patterns to improve user-experience. These included sites
leveraging image CDNs, &lt;a href=&quot;https://web.dev/fast/reduce-network-payloads-using-text-compression/codelab-text-compression-brotli&quot;&gt;Brotli
compression&lt;/a&gt;,
smart JavaScript serving and prefetching to speed up their pages. &lt;a href=&quot;https://www.youtube.com/watch?v=YJGCZCaIZkQ&amp;amp;feature=youtu.be&quot; rel=&quot;noopener&quot;&gt;Watch the
talk&lt;/a&gt; to learn
more :)&lt;/p&gt;
</content>
    <author>
      <name>Katie Hempenius</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Rendering on the Web</title>
    <link href="https://web.dev/rendering-on-the-web/"/>
    <updated>2019-02-06T00:00:00Z</updated>
    <id>https://web.dev/rendering-on-the-web/</id>
    <content type="html" mode="escaped">&lt;p&gt;As developers, we are often faced with decisions that will affect the entire architecture of our applications. One of the core decisions web developers must make is where to implement logic and rendering in their application. This can be difficult, since there are a number of different ways to build a website.&lt;/p&gt;
&lt;p&gt;Our understanding of this space is informed by our work in Chrome talking to large sites over the past few years. Broadly speaking, we would encourage developers to consider server-side rendering or static rendering over a full rehydration approach.&lt;/p&gt;
&lt;p&gt;In order to better understand the architectures we&#39;re choosing from when we make this decision, we need to have a solid understanding of each approach and consistent terminology to use when speaking about them. The differences between these approaches help illustrate the trade-offs of rendering on the web through the lens of performance.&lt;/p&gt;
&lt;h2 id=&quot;terminology&quot;&gt;Terminology &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#terminology&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rendering&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server-side rendering (SSR):&lt;/strong&gt; rendering a client-side or universal app to HTML on the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client-side rendering (CSR):&lt;/strong&gt; rendering an app in a browser via JavaScript to modify the DOM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rehydration:&lt;/strong&gt; &amp;quot;booting up&amp;quot; JavaScript views on the client such that they reuse the server-rendered HTML&#39;s DOM tree and data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prerendering:&lt;/strong&gt; running a client-side application at build time to capture its initial state as static HTML.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/ttfb/&quot;&gt;Time to First Byte (TTFB)&lt;/a&gt;:&lt;/strong&gt; seen as the time between clicking a link and the first bit of content coming in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint (FCP)&lt;/a&gt;:&lt;/strong&gt; the time when requested content (article body, etc) becomes visible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt;:&lt;/strong&gt; seen as a representative metric that assesses whether a page is responding consistently fast to user inputs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time (TBT)&lt;/a&gt;:&lt;/strong&gt; A &lt;a href=&quot;https://almanac.httparchive.org/en/2022/performance#inp-and-tbt&quot; rel=&quot;noopener&quot;&gt;proxy metric for INP&lt;/a&gt;, which calculates the amount of time the main thread was blocked during page load.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;server-side-rendering&quot;&gt;Server-side rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#server-side-rendering&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Server-side rendering generates the full HTML for a page on the server in response to navigation. This avoids additional round-trips for data fetching and templating on the client, since it&#39;s handled before the browser gets a response.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Server-side rendering generally produces a fast FCP. Running page logic and rendering on the server makes it possible to avoid sending lots of JavaScript to the client. This helps to reduce a page&#39;s TBT, which can also lead to a lower INP, as the main thread is not blocked as often during page load. When the main thread is blocked less often, user interactions will have more opportunities run sooner. This makes sense, since with server-side rendering, you&#39;re really just sending text and links to the user&#39;s browser. This approach can work well for a large spectrum of device and network conditions, and opens up interesting browser optimizations like streaming document parsing.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing server-side rendering and JS execution affecting FCP and TTI.&quot; decoding=&quot;async&quot; height=&quot;494&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WOL6PIpIQHpqsgtKwbJv.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With server-side rendering, users are less likely to be left waiting for CPU-bound JavaScript to run before they can use your site. Even where &lt;a href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/&quot;&gt;third-party JS&lt;/a&gt; can&#39;t be avoided, using server-side rendering to reduce your own first-party &lt;a href=&quot;https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4&quot; rel=&quot;noopener&quot;&gt;JavaScript costs&lt;/a&gt; can give you more &lt;a href=&quot;https://medium.com/@addyosmani/start-performance-budgeting-dabde04cf6a3&quot; rel=&quot;noopener&quot;&gt;budget&lt;/a&gt; for the rest. However, there is one potential trade-off with this approach: generating pages on the server takes time, which can may result in a higher TTFB.&lt;/p&gt;
&lt;p&gt;Whether server-side rendering is enough for your application largely depends on what type of experience you are building. There is a long-standing debate over the correct applications of server-side rendering versus client-side rendering, but it&#39;s important to remember that you can opt to use server-side rendering for some pages and not others. Some sites have adopted hybrid rendering techniques with success. &lt;a href=&quot;https://medium.com/dev-channel/a-netflix-web-performance-case-study-c0bcde26a9d9&quot; rel=&quot;noopener&quot;&gt;Netflix&lt;/a&gt; server-renders its relatively static landing pages, while &lt;a href=&quot;https://dev.to/addyosmani/speed-up-next-page-navigations-with-prefetching-4285&quot; rel=&quot;noopener&quot;&gt;prefetching&lt;/a&gt; the JS for interaction-heavy pages, giving these heavier client-rendered pages a better chance of loading quickly.&lt;/p&gt;
&lt;p&gt;Many modern frameworks, libraries and architectures make it possible to render the same application on both the client and the server. These techniques can be used for server-side rendering. However, it&#39;s important to note that architectures where rendering happens both on the server &lt;em&gt;and&lt;/em&gt; on the client are their own class of solution with very different performance characteristics and tradeoffs. React users can use &lt;a href=&quot;https://react.dev/reference/react-dom/server&quot; rel=&quot;noopener&quot;&gt;server DOM APIs&lt;/a&gt; or solutions built atop them like &lt;a href=&quot;https://nextjs.org/&quot; rel=&quot;noopener&quot;&gt;Next.js&lt;/a&gt; for server-side rendering. Vue users can look at Vue&#39;s &lt;a href=&quot;https://vuejs.org/guide/scaling-up/ssr.html&quot; rel=&quot;noopener&quot;&gt;server-side rendering guide&lt;/a&gt; or &lt;a href=&quot;https://nuxtjs.org/&quot; rel=&quot;noopener&quot;&gt;Nuxt&lt;/a&gt;. Angular has &lt;a href=&quot;https://angular.io/guide/universal&quot; rel=&quot;noopener&quot;&gt;Universal&lt;/a&gt;. Most popular solutions employ some form of hydration though, so be aware of the approach in use before selecting a tool.&lt;/p&gt;
&lt;h2 id=&quot;static-rendering&quot;&gt;Static rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#static-rendering&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://frontarm.com/articles/static-vs-server-rendering/&quot; rel=&quot;noopener&quot;&gt;Static rendering&lt;/a&gt; happens at build-time. This apporach offers a fast FCP, and also a lower TBT and INP—assuming the amount of client-side JS is limited. Unlike server-side rendering, it also manages to achieve a consistently fast TTFB, since the HTML for a page doesn&#39;t have to be dynamically generated on the server. Generally, static rendering means producing a separate HTML file for each URL ahead of time. With HTML responses generated in advance, static renders can be deployed to multiple CDNs to take advantage of edge caching.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing static rendering and optional JS execution affecting FCP and TTI.&quot; decoding=&quot;async&quot; height=&quot;613&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SRsl2UcHyJquzuJkdTHR.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Solutions for static rendering come in all shapes and sizes. Tools like &lt;a href=&quot;https://www.gatsbyjs.org/&quot; rel=&quot;noopener&quot;&gt;Gatsby&lt;/a&gt; are designed to make developers feel like their application is being rendered dynamically rather than generated as a build step. Static site generation tools such as &lt;a href=&quot;https://www.11ty.dev/&quot; rel=&quot;noopener&quot;&gt;11ty&lt;/a&gt;, &lt;a href=&quot;https://jekyllrb.com/&quot; rel=&quot;noopener&quot;&gt;Jekyll&lt;/a&gt;, and &lt;a href=&quot;https://metalsmith.iooperationalizing-node-js-for-server-side-rendering-c5ba718acfc9speedier-server-side-rendering-in-react-16-with-component-caching-e8aa677929b1/&quot; rel=&quot;noopener&quot;&gt;Metalsmith&lt;/a&gt; embrace their static nature, providing a more template-driven approach.&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; Abstractions of popular frameworks such as Next.js or Nuxt offer both static rendering and server-side rendering. This allows developers to opt into static rendering for pages that qualify, or use server-side rendering for pages that need to be dynamically generated in response to a request. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;One of the downsides to static rendering is that individual HTML files must be generated for every possible URL. This can be challenging or even infeasible when you can&#39;t predict what those URLs will be ahead of time, or for sites with a large number of unique pages.&lt;/p&gt;
&lt;p&gt;React users may be familiar with Gatsby, &lt;a href=&quot;https://nextjs.org/learn/excel/static-html-export/&quot; rel=&quot;noopener&quot;&gt;Next.js static export&lt;/a&gt; or &lt;a href=&quot;https://frontarm.com/navi/&quot; rel=&quot;noopener&quot;&gt;Navi&lt;/a&gt;—all of these make it convenient to author pages using components. However, it&#39;s important to understand the difference between static rendering and prerendering: static rendered pages are interactive without the need to execute much client-side JavaScript, whereas prerendering improves the FCP of a Single Page Application that must be booted on the client in order for pages to be truly interactive.&lt;/p&gt;
&lt;p&gt;If you&#39;re unsure whether a given solution is static rendering or prerendering, try disabling JavaScript and load the page you want to test. For statically rendered pages, most of the functionality will still exist without JavaScript enabled. For prerendered pages, there may still be some basic functionality like links, but most of the page will be inert.&lt;/p&gt;
&lt;p&gt;Another useful test is to use &lt;a href=&quot;https://developer.chrome.com/docs/devtools/device-mode/#network&quot; rel=&quot;noopener&quot;&gt;network throttling in Chrome DevTools&lt;/a&gt;, and observe how much JavaScript has been downloaded before a page becomes interactive. Prerendering generally requires more JavaScript to become interactive, and that JavaScript tends to be more complex than the &lt;a href=&quot;https://developer.mozilla.org/docs/Glossary/Progressive_Enhancement&quot; rel=&quot;noopener&quot;&gt;progressive enhancement&lt;/a&gt; approach used by static rendering.&lt;/p&gt;
&lt;h2 id=&quot;server-side-rendering-versus-static-rendering&quot;&gt;Server-side rendering versus static rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#server-side-rendering-versus-static-rendering&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Server-side rendering is not a silver bullet—its dynamic nature can come with significant compute overhead costs. Many server-side rendering solutions don&#39;t flush early, can delay TTFB, or double the data being sent (for example, inlined state used by JavaScript on the client). In React, &lt;code&gt;renderToString()&lt;/code&gt; can be slow as it&#39;s synchronous and single-threaded. &lt;a href=&quot;https://react.dev/reference/react-dom/server&quot; rel=&quot;noopener&quot;&gt;Newer React server DOM APIs&lt;/a&gt; supporting streaming, which can get the initial part of an HTML response to the browser sooner while the rest of it is still being generated on the server.&lt;/p&gt;
&lt;p&gt;Getting server-side rendering &amp;quot;right&amp;quot; can involve finding or building a solution for &lt;a href=&quot;https://medium.com/@reactcomponentcaching/&quot; rel=&quot;noopener&quot;&gt;component caching&lt;/a&gt;, managing memory consumption, applying &lt;a href=&quot;https://speakerdeck.com/maxnajim/hastening-react-ssr-with-component-memoization-and-templatization&quot; rel=&quot;noopener&quot;&gt;memoization&lt;/a&gt; techniques, and other concerns. You&#39;re generally processing/rebuilding the same application multiple times—once on the client and once on the server. Just because server-side rendering can make something show up sooner doesn&#39;t suddenly mean you have less work to do—if you have a lot of work on the client after a server-generated HTML response arrives on the client, this can still lead to higher TBT and INP for your website.&lt;/p&gt;
&lt;p&gt;Server-side rendering produces HTML on-demand for each URL, but can be slower than just serving static rendered content. If you can put in the additional leg-work, server-side rendering plus &lt;a href=&quot;https://freecontent.manning.com/caching-in-react/&quot; rel=&quot;noopener&quot;&gt;HTML caching&lt;/a&gt; can significantly reduce server render time. The upside to server-side rendering is the ability to pull more &amp;quot;live&amp;quot; data and respond to a more complete set of requests than is possible with static rendering. Pages requiring personalization are a concrete example of the type of request that would not work well with static rendering.&lt;/p&gt;
&lt;p&gt;Server-side rendering can also present interesting decisions when building a &lt;a href=&quot;https://web.dev/progressive-web-apps/&quot;&gt;PWA&lt;/a&gt;: is it better to use full-page &lt;a href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview/&quot; rel=&quot;noopener&quot;&gt;service worker&lt;/a&gt; caching, or just server-render individual pieces of content?&lt;/p&gt;
&lt;h2 id=&quot;client-side-rendering&quot;&gt;Client-side rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#client-side-rendering&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Client-side rendering means rendering pages directly in the browser with JavaScript. All logic, data fetching, templating and routing are handled on the client rather than the server. The effective outcome is that more passed to the user&#39;s device from the server, and that comes with its own set of trade-offs.&lt;/p&gt;
&lt;p&gt;Client-side rendering can be difficult to get and keep fast for mobile devices. If minimal work is done, client-side rendering can approach the performance of pure server-side rendering, keeping a &lt;a href=&quot;https://mobile.twitter.com/HenrikJoreteg/status/1039744716210950144&quot; rel=&quot;noopener&quot;&gt;tight JavaScript budget&lt;/a&gt; and delivering value in as few &lt;a href=&quot;https://en.wikipedia.org/wiki/Round-trip_delay_time&quot; rel=&quot;noopener&quot;&gt;round-trips&lt;/a&gt; as possible. Critical scripts and data can be delivered sooner using &lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt;, which gets the parser working for you sooner. Patterns like &lt;a href=&quot;https://web.dev/apply-instant-loading-with-prpl/&quot;&gt;PRPL&lt;/a&gt; are also worth evaluating in order to ensure initial and subsequent navigations feel instant.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing client-side rendering affecting FCP and TTI.&quot; decoding=&quot;async&quot; height=&quot;322&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JFxoxQe847ntctVOdn5u.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The primary downside to client-side rendering is that the amount of JavaScript required tends to grow as an application grows, which can have negative effects on a page&#39;s INP. This becomes especially difficult with the addition of new JavaScript libraries, polyfills and third-party code, which compete for processing power and must often be processed before a page&#39;s content can be rendered.&lt;/p&gt;
&lt;p&gt;Experiences that use client-side rendering that rely on large JavaScript bundles should consider &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;aggressive code-splitting&lt;/a&gt; to lower TBT and INP during page load, and be sure to lazy-load JavaScript—&amp;quot;serve only what you need, when you need it&amp;quot;. For experiences with little or no interactivity, server-side rendering can represent a more scalable solution to these issues.&lt;/p&gt;
&lt;p&gt;For folks building single page applications, identifying core parts of the user interface shared by most pages means you can apply the &lt;a href=&quot;https://developer.chrome.com/blog/app-shell/&quot; rel=&quot;noopener&quot;&gt;application shell caching&lt;/a&gt; technique. Combined with service workers, this can dramatically improve perceived performance on repeat visits, as the application shell HTML and its dependencies can be loaded from &lt;code&gt;CacheStorage&lt;/code&gt; very quickly.&lt;/p&gt;
&lt;h2 id=&quot;combining-server-side-rendering-and-client-side-rendering-via-rehydration&quot;&gt;Combining server-side rendering and client-side rendering via rehydration &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#combining-server-side-rendering-and-client-side-rendering-via-rehydration&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This approach attempts to smooth over the trade-offs between client-side rendering and server-side rendering by doing both. Navigation requests like full page loads or reloads are handled by a server that renders the application to HTML, then the JavaScript and data used for rendering is embedded into the resulting document. When done carefully, this achieves a fast FCP just like server-side rendering, then &amp;quot;picks up&amp;quot; by rendering again on the client using a technique called &lt;a href=&quot;https://react.dev/reference/react-dom/client/hydrateRoot&quot; rel=&quot;noopener&quot;&gt;(re)hydration&lt;/a&gt;. This is an effective solution, but it can come with considerable performance drawbacks.&lt;/p&gt;
&lt;p&gt;The primary downside of server-side rendering with rehydration is that it can have a significant negative impact on TBT and INP, even if it improves FCP. Server-side rendered pages can deceptively appear to be loaded and interactive, but can&#39;t actually respond to input until the client-side scripts for components are executed and event handlers have been attached. This can take seconds or even minutes on mobile.&lt;/p&gt;
&lt;p&gt;Perhaps you&#39;ve experienced this yourself—for a period of time after it looks like a page has loaded, clicking or tapping does nothing. This quickly becoming frustrating, as the user is left to wonder why nothing is happening when they try to interact with the page.&lt;/p&gt;
&lt;h3 id=&quot;a-rehydration-problem-one-app-for-the-price-of-two&quot;&gt;A rehydration problem: one app for the price of two &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#a-rehydration-problem-one-app-for-the-price-of-two&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rehydration issues can often be worse than delayed interactivity due to JavaScript. In order for the client-side JavaScript to be able to accurately &amp;quot;pick up&amp;quot; where the server left off without having to re-request all of the data the server used to render its HTML, current server-side rendering solutions generally serialize the response from a UI&#39;s data dependencies into the document as script tags. The resulting HTML document contains a high level of duplication:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;HTML document containing serialized UI, inlined data and a bundle.js script&quot; decoding=&quot;async&quot; height=&quot;447&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CwHQGXjA4qRyVa4pGdXT.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;As you can see, the server is returning a description of the application&#39;s UI in response to a navigation request, but it&#39;s also returning the source data used to compose that UI, and a complete copy of the UI&#39;s implementation which then boots up on the client. Only after &lt;code&gt;bundle.js&lt;/code&gt; has finished loading and executing does this UI become interactive.&lt;/p&gt;
&lt;p&gt;Performance metrics collected from real websites using server-side rendering and rehydration indicate its use should be discouraged. Ultimately, the reason comes down to the user experience: it&#39;s extremely easy to end up leaving users in an &amp;quot;uncanny valley&amp;quot;, where interactivity feels absent even though the page &lt;em&gt;appears&lt;/em&gt; to be ready.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing client rendering negatively affecting TTI.&quot; decoding=&quot;async&quot; height=&quot;270&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/aXn4IcnNfFb2SvaYJPWU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;There&#39;s hope for server-side rendering with rehydration, though. In the short term, only using server-side rendering for highly cacheable content can reduce TTFB, producing similar results to prerendering. Rehydrating &lt;a href=&quot;https://www.emberjs.com/blog/2017/10/10/glimmer-progress-report.html&quot; rel=&quot;noopener&quot;&gt;incrementally&lt;/a&gt;, progressively, or partially may be the key to making this technique more viable in the future.&lt;/p&gt;
&lt;h2 id=&quot;streaming-server-side-rendering-and-progressive-rehydration&quot;&gt;Streaming server-side rendering and progressive rehydration &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#streaming-server-side-rendering-and-progressive-rehydration&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Server-side rendering has had a number of developments over the last few years.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mxstbr.com/thoughts/streaming-ssr&quot; rel=&quot;noopener&quot;&gt;Streaming server-side rendering&lt;/a&gt; allows you to send HTML in chunks that the browser can progressively render as it&#39;s received. This can result in a fast FCP, as markup arrives to users faster. In React, streams being asynchronous in [&lt;code&gt;renderToPipeableStream()&lt;/code&gt;]—compared to synchronous &lt;code&gt;renderToString()&lt;/code&gt;—means backpressure is handled well.&lt;/p&gt;
&lt;p&gt;Progressive rehydration is also worth considering, and something that React has &lt;a href=&quot;https://github.com/facebook/react/pull/14717&quot; rel=&quot;noopener&quot;&gt;landed&lt;/a&gt;. With this approach, individual pieces of a server-rendered application are &amp;quot;booted up&amp;quot; over time, rather than the current common approach of initializing the entire application at once. This can help reduce the amount of JavaScript required to make pages interactive, since client-side upgrading of low priority parts of the page can be deferred to prevent blocking the main thread, allowing user interactions to occur sooner after the user initiates them.&lt;/p&gt;
&lt;p&gt;Progressive rehydration can also help avoid one of the most common server-side rendering rehydration pitfalls, where a server-rendered DOM tree gets destroyed and then immediately rebuilt—most often because the initial synchronous client-side render required data that wasn&#39;t quite ready, perhaps awaiting resolution of a &lt;code&gt;Promise&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;partial-rehydration&quot;&gt;Partial rehydration &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#partial-rehydration&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Partial rehydration has proven difficult to implement. This approach is an extension of the idea of progressive rehydration, where the individual pieces (components/views/trees) to be progressively rehydrated are analyzed and those with little interactivity or no reactivity are identified. For each of these mostly-static parts, the corresponding JavaScript code is then transformed into inert references and decorative functionality, reducing their client-side footprint to nearly zero.&lt;/p&gt;
&lt;p&gt;The partial hydration approach comes with its own issues and compromises. It poses some interesting challenges for caching, and client-side navigation means we can&#39;t assume server-rendered HTML for inert parts of the application will be available without a full page load.&lt;/p&gt;
&lt;h3 id=&quot;trisomorphic-rendering&quot;&gt;Trisomorphic rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#trisomorphic-rendering&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If &lt;a href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview/&quot; rel=&quot;noopener&quot;&gt;service workers&lt;/a&gt; are an option for you, &amp;quot;trisomorphic&amp;quot; rendering may also be of interest. It&#39;s a technique where you can use streaming server-side rendering for initial/non-JS navigations, and then have your service worker take on rendering of HTML for navigations after it has been installed. This can keep cached components and templates up to date and enables SPA-style navigations for rendering new views in the same session. This approach works best when you can share the same templating and routing code between the server, client page, and service worker.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram of Trisomorphic rendering, showing a browser and service worker communicating with the server.&quot; decoding=&quot;async&quot; height=&quot;504&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EnHAdI7a6mhv7iU81iRe.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;seo-considerations&quot;&gt;SEO considerations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#seo-considerations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Teams often factor in the impact of SEO when choosing a strategy for rendering on the web. Server-side rendering is often chosen for delivering a &amp;quot;complete looking&amp;quot; experience crawlers can interpret with ease. Crawlers &lt;a href=&quot;https://web.dev/discoverable/how-search-works&quot;&gt;may understand JavaScript&lt;/a&gt;, but there are often &lt;a href=&quot;https://developers.google.com/search/docs/guides/rendering&quot; rel=&quot;noopener&quot;&gt;limitations&lt;/a&gt; worth being aware of in how they render. Client-side rendering can work, but often not without additional testing and leg-work. More recently, &lt;a href=&quot;https://developers.google.com/search/docs/advanced/javascript/dynamic-rendering&quot; rel=&quot;noopener&quot;&gt;dynamic rendering&lt;/a&gt; has also become an option worth considering if your architecture depends heavily on client-side JavaScript.&lt;/p&gt;
&lt;p&gt;When in doubt, the &lt;a href=&quot;https://search.google.com/test/mobile-friendly&quot; rel=&quot;noopener&quot;&gt;mobile friendly test tool&lt;/a&gt; is invaluable for testing that your chosen approach does what you&#39;re hoping for. It shows a visual preview of how any page appears to Google&#39;s crawler, the serialized HTML content found (after JavaScript executed), and any errors encountered during rendering.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshot of the Mobile Friendly Test UI.&quot; decoding=&quot;async&quot; height=&quot;817&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/2OH46CfDEvODtabXpKZp.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#wrapping-up&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When deciding on an approach to rendering, measure and understand what your bottlenecks are. Consider whether static rendering or server-side rendering can get you most of the way there. It&#39;s perfectly okay to mostly ship HTML with minimal JavaScript to get an experience interactive. Here&#39;s a handy infographic showing the server-client spectrum:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Infographic showing the spectrum of options described in this article.&quot; decoding=&quot;async&quot; height=&quot;530&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FZ7p6ZImdJbM82E0ZwMF.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;credits&quot;&gt;Credits &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/rendering-on-the-web/#credits&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to everyone for their reviews and inspiration:&lt;/p&gt;
&lt;p&gt;Jeffrey Posnick,
Houssein Djirdeh,
Shubhie Panicker,
Chris Harrelson, and
Sebastian Markbåge&lt;/p&gt;
</content>
    <author>
      <name>Jason Miller</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Web Performance Made Easy - Google I/O 2018 edition</title>
    <link href="https://web.dev/web-performance-made-easy/"/>
    <updated>2018-08-21T00:00:00Z</updated>
    <id>https://web.dev/web-performance-made-easy/</id>
    <content type="html" mode="escaped">&lt;p&gt;We&#39;ve been pretty busy over the past year trying to figure out how to make the Web faster and
more performant. This led to new tools, approaches and libraries that we’d like share with you
in this article. In the first part, we’ll show you some optimization techniques we used in practice
when developing &lt;a href=&quot;https://github.com/google/oodle-demo&quot; rel=&quot;noopener&quot;&gt;The Oodles Theater app&lt;/a&gt;. In the second part,
we’ll talk about our experiments with predictive loading and the new
&lt;a href=&quot;https://github.com/guess-js/guess&quot; rel=&quot;noopener&quot;&gt;Guess.js&lt;/a&gt; initiative.&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; Prefer a video to an article? You can watch the presentation on which this was based instead: &lt;/div&gt;&lt;/aside&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;Mv-l3-tJgGk&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-need-for-performance&quot;&gt;The need for performance &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#the-need-for-performance&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Internet gets heavier and heavier every year. If we check
&lt;a href=&quot;https://httparchive.org/reports/state-of-the-web&quot; rel=&quot;noopener&quot;&gt;the state of the web&lt;/a&gt; we can see that a median
page on mobile weights at about 1.5MB, with the majority of that being JavaScript and images.&lt;/p&gt;
&lt;p&gt;The growing size of the websites, together with other factors, like network latency,
CPU limitations, render blocking patterns or superfluous third-party code, contributes to
the complicated performance puzzle.&lt;/p&gt;
&lt;p&gt;Most users rate speed as being at the very top of the UX hierarchy of their needs. This isn&#39;t too
surprising, because you can&#39;t really do a whole lot until a page is finished loading. You can&#39;t
derive value from the page, you can&#39;t admire its aesthetics.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;UX hierarchy piramide&quot; decoding=&quot;async&quot; height=&quot;338&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Z1NCy55gqEtPfksngiqo.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 1.&lt;/strong&gt; How important is speed to users? (Speed Matters, Vol. 3)
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We know that performance matters to the users, but it can also feel like a secret discovering
where to start optimizing. Fortunately, there are tools that can help you on the way.&lt;/p&gt;
&lt;h2 id=&quot;lighthouse-a-base-for-performance-workflow&quot;&gt;Lighthouse - a base for performance workflow &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#lighthouse-a-base-for-performance-workflow&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; is a part of Chrome DevTools
that allows you to make an audit of your website, and gives you hints on how to make it better.&lt;/p&gt;
&lt;p&gt;We recently launched a bunch of
&lt;a href=&quot;https://developer.chrome.com/blog/lighthouse-load-performance/&quot; rel=&quot;noopener&quot;&gt;new performance audits&lt;/a&gt;
that are really useful in everyday development workflow.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;New Lighthouse audits&quot; decoding=&quot;async&quot; height=&quot;347&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fnXQDZFYbg9SDNagLlew.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 2.&lt;/strong&gt; New Lighthouse audits
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Let’s explore how you can take advantage of them on a practical example:
&lt;a href=&quot;https://oodle-demo.firebaseapp.com/&quot; rel=&quot;noopener&quot;&gt;The Oodles Theater app&lt;/a&gt;. It’s a little demo web app,
where you can try out some of our favourite interactive Google Doodles and even play a game or two.&lt;/p&gt;
&lt;p&gt;While building the app, we wanted to make sure that it was as performant as possible. The starting
point for optimization was a Lighthouse report.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse report for Oodles app&quot; decoding=&quot;async&quot; height=&quot;490&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/euuEKKlTGjpPfLVdyN1i.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 3.&lt;/strong&gt; Lighthouse report for Oodles app
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The initial performance of our app as seen on Lighthouse report was pretty terrible.
On a 3G network, the user needed to wait for 15 seconds for the first meaningful paint, or for
the app to get interactive. Lighthouse highlighted a ton of issues with our site, and the overall
performance score of &lt;strong&gt;23&lt;/strong&gt; mirrored exactly that.&lt;/p&gt;
&lt;p&gt;The page weighted about &lt;strong&gt;3.4MB&lt;/strong&gt; - we desperately needed to cut some fat.&lt;/p&gt;
&lt;p&gt;This started our first performance challenge: find things that we can easily remove without
affecting the overall experience.&lt;/p&gt;
&lt;h2 id=&quot;performance-optimization-opportunities&quot;&gt;Performance optimization opportunities &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#performance-optimization-opportunities&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;remove-unnecessary-resources&quot;&gt;Remove unnecessary resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#remove-unnecessary-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are some obvious things that can be safely removed:  whitespace and comments.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Gains from minification&quot; decoding=&quot;async&quot; height=&quot;325&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 586px) 586px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/fX7mxoJmL1y6ZYTuSp6A.png?auto=format&amp;w=1172 1172w&quot; width=&quot;586&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 4.&lt;/strong&gt; Minify and compress JavaScript and CSS
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Lighthouse highlights this opportunity in the &lt;strong&gt;Unminified CSS &amp;amp; JavaScript audit&lt;/strong&gt;. We were using
webpack for our build process, so in order to get minification we simply used the
&lt;a href=&quot;https://webpack.js.org/plugins/uglifyjs-webpack-plugin/&quot; rel=&quot;noopener&quot;&gt;Uglify JS plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Minification is a common task, so you should be able to find a ready-made solution for whichever
build process you happen to use.&lt;/p&gt;
&lt;p&gt;Another useful audit in that space is &lt;strong&gt;Enable text compression&lt;/strong&gt;. There is no reason to
send uncompressed files, and most of
the &lt;a href=&quot;https://developer.mozilla.org/docs/Glossary/CDN&quot; rel=&quot;noopener&quot;&gt;CDNs&lt;/a&gt; support this out of the
box these days.&lt;/p&gt;
&lt;p&gt;We were using &lt;a href=&quot;https://firebase.google.com/docs/hosting/&quot; rel=&quot;noopener&quot;&gt;Firebase Hosting&lt;/a&gt; to host our code,
and Firebase enables &lt;a href=&quot;https://www.gnu.org/software/gzip/&quot; rel=&quot;noopener&quot;&gt;gzipping&lt;/a&gt; by default, so by the sheer
virtue of hosting our code on a reasonable CDN we got that for free.&lt;/p&gt;
&lt;p&gt;While gzip is a very popular way of compressing, other mechanisms like
&lt;a href=&quot;https://github.com/google/zopfli&quot; rel=&quot;noopener&quot;&gt;Zopfli&lt;/a&gt; and &lt;a href=&quot;https://github.com/google/brotli&quot; rel=&quot;noopener&quot;&gt;Brotli&lt;/a&gt; are
getting traction as well. Brotli enjoys support in most browsers, and you can use a binary
to pre-compress your assets before sending them to the server.&lt;/p&gt;
&lt;h3 id=&quot;use-efficient-cache-policies&quot;&gt;Use efficient cache policies &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#use-efficient-cache-policies&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our next step was to ensure that we don’t send resources twice if unnecessary.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Inefficient cache policy&lt;/strong&gt; audit in Lighthouse helped us notice that we could be optimizing
our caching strategies in order to achieve exactly that. By setting a max-age expiration header
in our server, we made sure that on a repeated visit the user can reuse the resources they have
downloaded before.&lt;/p&gt;
&lt;p&gt;Ideally you should aim at caching as many resources as securely possible for the longest possible
period of time and provide validation tokens for efficient revalidation of the resources
that got updated.&lt;/p&gt;
&lt;h3 id=&quot;remove-unused-code&quot;&gt;Remove unused code &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#remove-unused-code&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far we removed the obvious parts of the unnecessary download, but what about the less obvious
parts? For example, unused code.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Code coverage in DevTools&quot; decoding=&quot;async&quot; height=&quot;275&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1FjR76i7lLptY08Djx1R.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 5.&lt;/strong&gt; Check code coverage
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Sometimes we include in our apps code that is not really necessary. This happens especially
if you work on your app for a longer period of time, your team or your dependencies change,
and sometimes an orphan library gets left behind. That&#39;s exactly what happened to us.&lt;/p&gt;
&lt;p&gt;At the beginning we were using Material Components library to quickly prototype our app.
In time we moved to a more custom look and feel and we forgot entirely about that library.
Fortunately, the &lt;strong&gt;code coverage&lt;/strong&gt; check helped us rediscover it in our bundle.&lt;/p&gt;
&lt;p&gt;You can check your code coverage stats in DevTools, both for the runtime as well as load time of
your application. You can see the two big red stripes in the bottom screenshot - we had over 95%
of our CSS unused, and a big bunch of JavaScript as well.&lt;/p&gt;
&lt;p&gt;Lighthouse also picked up this issue in the unused CSS rules audit. It showed a potential saving
of over 400kb. So we got back to our code and we removed both the JavaScript and CSS part
of that library.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;If we drop MVC adapter our styles drop to 10KB&quot; decoding=&quot;async&quot; height=&quot;272&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/WjgWvff6PiQwMrRL5ObT.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 6.&lt;/strong&gt; If we drop MVC adapter our styles drop to 10KB!
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This brought our CSS bundle down 20-fold, which is pretty good for a tiny, two-line-long commit.&lt;/p&gt;
&lt;p&gt;Of course, it made our performance score go up, and also the
&lt;a href=&quot;https://developer.akamai.com/blog/2017/04/12/gauge-user-experience-time-interactive/&quot; rel=&quot;noopener&quot;&gt;Time to Interactive&lt;/a&gt;
got much better.&lt;/p&gt;
&lt;p&gt;However, with changes like this, it’s not enough to check your metrics and scores alone.
Removing actual code is never risk-free, so you should always look out for potential regressions.&lt;/p&gt;
&lt;p&gt;Our code was unused in 95% - there’s still this 5% somewhere. Apparently one of our components
was still using the styles from that library - the little arrows in the doodle slider. Because it
was so small though, we could just go and manually incorporate those styles back into the buttons.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Buttons got broken by missing library&quot; decoding=&quot;async&quot; height=&quot;196&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 588px) 588px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ah5S9a2Ki5oq9lHlzrGK.png?auto=format&amp;w=1176 1176w&quot; width=&quot;588&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 7.&lt;/strong&gt; One component was still using the removed library
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So if you remove code, just make sure you have a proper testing workflow in place to help you
guard against potential visual regressions.&lt;/p&gt;
&lt;h3 id=&quot;avoid-enormous-network-payloads&quot;&gt;Avoid enormous network payloads &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#avoid-enormous-network-payloads&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We know that large resources can slow down web page loads. They can cost our users money and
they can have a big impact on their data plans, so it&#39;s really important to be mindful of this.&lt;/p&gt;
&lt;p&gt;Lighthouse was able to detect that we had an issue with some of our network payloads using the
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/total-byte-weight&quot; rel=&quot;noopener&quot;&gt;Enormous network payload&lt;/a&gt;
audit.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Detect enormous network payloads&quot; decoding=&quot;async&quot; height=&quot;473&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QvmoocK29nYcmZBiVP6o.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 8.&lt;/strong&gt; Detect enormous network payloads
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here we saw that we had over 3mb worth of code that was being shipped down – which is quite a lot,
especially on mobile.&lt;/p&gt;
&lt;p&gt;At the very top of this list, Lighthouse highlighted that we had a JavaScript vendor bundle
that was 2mb of uncompressed code. This is also a problem highlighted by webpack.&lt;/p&gt;
&lt;p&gt;As the saying goes: the fastest request is the one that&#39;s not made.&lt;/p&gt;
&lt;p&gt;Ideally you should be measuring the value of every single asset you&#39;re serving down to your users,
measuring the performance of those assets, and making a call on whether it&#39;s worth actually shipping
down with the initial experience. Because sometimes these assets can be deferred, or lazily loaded,
or processed during idle time.&lt;/p&gt;
&lt;p&gt;In our case, because we&#39;re dealing with a lot of JavaScript bundles, we were fortunate because
the JavaScript community has a rich set of JavaScript bundle auditing tools.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;JavaScript bundle auditing&quot; decoding=&quot;async&quot; height=&quot;398&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GLlPM0f586jIEl1xRVoQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 9.&lt;/strong&gt; JavaScript bundle auditing
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We started off with webpack bundle analyzer, which informed us that we were including a
dependency called unicode which was 1.6mb of parsed JavaScript, so quite a lot.&lt;/p&gt;
&lt;p&gt;We then went over to our editor and using the
&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost&quot; rel=&quot;noopener&quot;&gt;Import Cost Plugin for Visual code&lt;/a&gt;
we were able to
visualize the cost of every module that we were importing. This allowed us to discover which
component was including code that was referencing this module.&lt;/p&gt;
&lt;p&gt;We then switched over to another tool, &lt;a href=&quot;https://bundlephobia.com/&quot; rel=&quot;noopener&quot;&gt;BundlePhobia&lt;/a&gt;. This is a tool
which allows you to enter in the name of any NPM package and actually see what its minified and
gzipped size is estimated to be. We found a nice alternative for the slug module we were using
that only weighed 2.2kb, and so we switched that up.&lt;/p&gt;
&lt;p&gt;This had a big impact on our performance. Between this change and discovering other opportunities
to trim down our JavaScript bundle size, we saved 2.1mb of code.&lt;/p&gt;
&lt;p&gt;We saw 65% improvements overall, once you factor in the gzipped and minified size of these bundles.
And we found that this was really worth doing as a process.&lt;/p&gt;
&lt;p&gt;So, in general, try to eliminate unnecessary downloads in your sites and apps.
Make an inventory of your assets and measure their performance impact can make a really big
difference, so make sure that you&#39;re auditing your assets fairly regularly.&lt;/p&gt;
&lt;h3 id=&quot;lower-javascript-boot-up-time-with-code-splitting&quot;&gt;Lower JavaScript boot-up time with code splitting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#lower-javascript-boot-up-time-with-code-splitting&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although large network payloads can have a big impact on our app, there&#39;s another thing that can
have a really big impact, and that is JavaScript.&lt;/p&gt;
&lt;p&gt;JavaScript is your
&lt;a href=&quot;https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e&quot; rel=&quot;noopener&quot;&gt;most expensive asset&lt;/a&gt;.
On mobile, if you&#39;re sending
down large bundles of JavaScript, it can delay how soon your users are able to interact with your
user interface components. That means they can be tapping on UI without anything meaningful
actually happening. So it&#39;s important for us to understand why JavaScript costs so much.&lt;/p&gt;
&lt;p&gt;This is how a browser processes JavaScript.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;JavaScript processing&quot; decoding=&quot;async&quot; height=&quot;328&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 589px) 589px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8cEoOq6exz9QLDLfNB6q.png?auto=format&amp;w=1178 1178w&quot; width=&quot;589&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 10.&lt;/strong&gt; JavaScript processing
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We first of all have to download that script, we have a JavaScript engine which then needs to parse
that code, needs to compile it and execute it.&lt;/p&gt;
&lt;p&gt;Now these phases are something that don&#39;t take a whole lot of time on a high-end device like
a desktop machine or a laptop, maybe even a high-end phone. But on a median mobile phone this
process can take anywhere between five and ten times longer. This is what delays interactivity,
so it&#39;s important for us to try trimming this down.&lt;/p&gt;
&lt;p&gt;To help you discover these issues with your app, we introduced a new
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time&quot; rel=&quot;noopener&quot;&gt;JavaScript boot-up time audit&lt;/a&gt; to Lighthouse.&lt;/p&gt;
&lt;figure&gt;
 &lt;img alt=&quot;JavaScript boot up time&quot; decoding=&quot;async&quot; height=&quot;223&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KDj3tb1r3VrmPbrDo1kr.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 11.&lt;/strong&gt; JavaScript boot up time audit
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And in the case of the Oodle app, it told us that we had 1.8 seconds of time spent in JavaScript
boot-up. What was happening was that we were statically importing in all of our routes and
components into one monolithic JavaScript bundle.&lt;/p&gt;
&lt;p&gt;One technique for working around this is using code splitting.&lt;/p&gt;
&lt;figure class=&quot;float-right&quot;&gt;
  &lt;img alt=&quot;Code splitting is like pizza&quot; decoding=&quot;async&quot; height=&quot;257&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 300px) 300px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RH8lhpMF9WUaqtLD69VB.png?auto=format&amp;w=600 600w&quot; width=&quot;300&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Code splitting is this notion of instead of giving your users a whole pizza’s worth of JavaScript,
what if you only gave them one slice at a time as they needed it?&lt;/p&gt;
&lt;p&gt;Code splitting can be applied at a route level or a component level. It works great with React and
React Loadable, Vue.js, Angular, Polymer, Preact, and multiple other libraries.&lt;/p&gt;
&lt;p&gt;We incorporated code splitting into our application, we switched over from static imports to
dynamic imports, allowing us to asynchronously lazy load code in as we needed it.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Code splitting with dynamic imports&quot; decoding=&quot;async&quot; height=&quot;382&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a0wDugnVMM1WjNyAvLEv.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 13.&lt;/strong&gt; Code splitting with dynamic imports
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The impact this had was both shrinking down the size of our bundles, but also decreasing our
JavaScript boot up time. It took it down to 0.78 seconds, making the app 56% faster.&lt;/p&gt;
&lt;p&gt;In general, if you&#39;re building a JavaScript-heavy experience, be sure to only send code to
the user that they need.&lt;/p&gt;
&lt;p&gt;Take advantage of concepts like code splitting, explore ideas like tree shaking, and check out
&lt;a href=&quot;https://github.com/GoogleChromeLabs/webpack-libs-optimizations&quot; rel=&quot;noopener&quot;&gt;webpack-libs-optimizations&lt;/a&gt;
repo for a few ideas on how you can trim down your library size if you happen to be using webpack.&lt;/p&gt;
&lt;h3 id=&quot;optimize-images&quot;&gt;Optimize images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#optimize-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Image loading performance joke&quot; decoding=&quot;async&quot; height=&quot;323&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 586px) 586px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UeTyldEMnrV4Bn67mdJO.png?auto=format&amp;w=1172 1172w&quot; width=&quot;586&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;In the Oodle app we&#39;re using a lot of images. Unfortunately, Lighthouse was much less enthusiastic
about it than we were. As a matter of fact, we failed on all three image-related audits.&lt;/p&gt;
&lt;p&gt;We forgot to optimize our images, we were not sizing them correctly, and also we could get some
gain from using other image formats.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Image audits&quot; decoding=&quot;async&quot; height=&quot;325&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 588px) 588px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lH2NxcPFVetLrvV7KZOG.png?auto=format&amp;w=1176 1176w&quot; width=&quot;588&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 14.&lt;/strong&gt; Lighthouse image audits
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We started with optimizing our images.&lt;/p&gt;
&lt;p&gt;For one-off optimization round you can use visual tools like
&lt;a href=&quot;https://imageoptim.com/mac&quot; rel=&quot;noopener&quot;&gt;ImageOptim&lt;/a&gt; or &lt;a href=&quot;https://www.xnview.com/en/xnconvert/&quot; rel=&quot;noopener&quot;&gt;XNConvert&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A more automated approach is to add an image optimization step to your build process, with
libraries like &lt;a href=&quot;https://github.com/imagemin/imagemin&quot; rel=&quot;noopener&quot;&gt;imagemin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This way you make sure that the images added in the future get optimized automatically.
Some CDNs, for example &lt;a href=&quot;https://www.akamai.com/&quot; rel=&quot;noopener&quot;&gt;Akamai&lt;/a&gt; or third-party solutions like
&lt;a href=&quot;https://cloudinary.com/&quot; rel=&quot;noopener&quot;&gt;Cloudinary&lt;/a&gt;, &lt;a href=&quot;https://www.fastly.com/&quot; rel=&quot;noopener&quot;&gt;Fastly&lt;/a&gt;
or &lt;a href=&quot;https://uploadcare.com/&quot; rel=&quot;noopener&quot;&gt;Uploadcare&lt;/a&gt; offer you comprehensive
image optimization solutions. so you can also simply host your images on those services.&lt;/p&gt;
&lt;p&gt;If you don&#39;t want to do that because of the cost, or latency issues, projects like
&lt;a href=&quot;http://thumbor.org/&quot; rel=&quot;noopener&quot;&gt;Thumbor&lt;/a&gt; or &lt;a href=&quot;https://github.com/imazen/imageflow&quot; rel=&quot;noopener&quot;&gt;Imageflow&lt;/a&gt; offer
self-hosted alternatives.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Before and after optimization&quot; decoding=&quot;async&quot; height=&quot;164&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 513px) 513px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/1Jyf3Tn6cA4Z2slp26QF.png?auto=format&amp;w=1026 1026w&quot; width=&quot;513&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 15.&lt;/strong&gt; Before and after optimization
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Our background PNG was flagged in webpack as big, and rightly so. After sizing it correctly to
the viewport and running it through ImageOptim, we went down to 100kb, which is acceptable.&lt;/p&gt;
&lt;p&gt;Repeating this for multiple images on our site allowed us to bring down the overall page weight
significantly.&lt;/p&gt;
&lt;h3 id=&quot;use-the-right-format-for-animated-content&quot;&gt;Use the right format for animated content &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#use-the-right-format-for-animated-content&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;GIFs can get really expensive. Surprisingly, the GIF format was never intended as an animation
platform in the first place. Therefore, switching to a more suitable video format offers you large
savings in terms of file size.&lt;/p&gt;
&lt;p&gt;In Oodle app, we were using a GIF as an intro sequence on the home page. According to Lighthouse,
we could be saving over 7mb by switching to a more efficient video format. Our clip weighted about
7.3mb, way too much for any reasonable website, so instead we turned it into a video element with
two source files - an mp4 and WebM for wider browser support.&lt;/p&gt;
&lt;figure style=&quot;text-align: center;&quot;&gt;
    &lt;img alt=&quot;Replace Animated GIFs with video&quot; decoding=&quot;async&quot; height=&quot;302&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PXR11JRtDWpkMEXrx48Z.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 16.&lt;/strong&gt; Replace Animated GIFs with video
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We used the &lt;a href=&quot;https://ffmpeg.org/&quot; rel=&quot;noopener&quot;&gt;FFmpeg&lt;/a&gt; tool to convert our animation GIF into the mp4 file.
The WebM format offers you even larger savings - the ImageOptim API can do such conversion for you.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;ffmpeg -i animation.gif -b:v &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; -crf &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt; -vf &lt;span class=&quot;token assign-left variable&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;:-1 video.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We managed to save over 80% of our overall weight thanks to this conversion. This brought
us down to around 1mb.&lt;/p&gt;
&lt;p&gt;Still, 1mb is a large resource to push down the wire, especially for a user on a restricted
bandwidth. Luckily we could use
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/NetworkInformation/effectiveType&quot; rel=&quot;noopener&quot;&gt;Effective Type API&lt;/a&gt;
to realize they&#39;re on a slow bandwidth, and give them a much smaller JPEG instead.&lt;/p&gt;
&lt;p&gt;This interface uses the effective round-trip time and downing values to estimate the network type
the user is using. It simply returns a string, slow 2G, 2G, 3G or 4G. So depending on
this value, if the user is on below 4G we could replace the video element with the image.&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;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;effectiveType&lt;span class=&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It does remove a little bit from the experience, but at least the site is usable on a slow
connection.&lt;/p&gt;
&lt;h3 id=&quot;lazy-load-off-screen-images&quot;&gt;Lazy-load off-screen images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#lazy-load-off-screen-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Carousels, sliders, or really long pages often load images, even though the user cannot see them
on the page straight away.&lt;/p&gt;
&lt;p&gt;Lighthouse will flag this behavior in the off-screen images audit, and you can also see it
for yourself in the network panel of DevTools. If you see a lot of images incoming while only
a few are visible on the page, it means that maybe you could consider lazy loading them instead.&lt;/p&gt;
&lt;p&gt;Lazy loading is not yet supported natively in the browser, so we have to use JavaScript to add this
capability. We used &lt;a href=&quot;https://www.npmjs.com/package/lazysizes&quot; rel=&quot;noopener&quot;&gt;Lazysizes library&lt;/a&gt; to add lazy
loading behavior to our Oodle covers.&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 comment&quot;&gt;&amp;lt;!-- Import library --&gt;&lt;/span&gt;&lt;br /&gt;import lazysizes from &#39;lazysizes&#39;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- or --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazysizes.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Use it --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;lazyload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazyload&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-sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;auto&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-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;image2.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;data-srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image1.jpg 300w,&lt;br /&gt;    image2.jpg 600w,&lt;br /&gt;    image3.jpg 900w&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;Lazysizes is smart because it does not only track the visibility changes of the element, but it
also proactively prefetches elements that are near the view for the optimal user experience.
It also offers an optional integration of the &lt;code&gt;IntersectionObserver&lt;/code&gt;, which gives you very
efficient visibility lookups.&lt;/p&gt;
&lt;p&gt;After this change our images are being fetched on-demand. If you want to dig deeper into that
topic, check out &lt;a href=&quot;https://images.guide/&quot; rel=&quot;noopener&quot;&gt;images.guide&lt;/a&gt; - a very handy and comprehensive resource.&lt;/p&gt;
&lt;h3 id=&quot;help-browser-deliver-critical-resources-early&quot;&gt;Help browser deliver critical resources early &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#help-browser-deliver-critical-resources-early&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Not every byte that&#39;s shipped down the wire to the browser has the same degree of importance,
and the browser knows this. A lot of browsers have heuristics to decide what they should be
fetching first. So sometimes they&#39;ll fetch CSS before images or scripts.&lt;/p&gt;
&lt;p&gt;Something that could be useful is us, as authors of the page, informing the browser what&#39;s
actually really important to us. Thankfully, over the last couple of years browser vendors have
been adding a number of features to help us with this, e.g.
&lt;a href=&quot;https://web.dev/web-performance-made-easy/(https://www.keycdn.com/blog/resource-hints/)&quot;&gt;resource hints&lt;/a&gt; like &lt;code&gt;link rel=preconnect&lt;/code&gt;,
or &lt;code&gt;preload&lt;/code&gt; or &lt;code&gt;prefetch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These capabilities that were brought to the web platform help the browser fetch the right thing
at the right time, and they can be a little bit more efficient than some of the custom loading,
logic-based approaches that are done using script instead.&lt;/p&gt;
&lt;p&gt;Let&#39;s see how Lighthouse actually guides us towards using some of these features effectively.&lt;/p&gt;
&lt;p&gt;The first thing Lighthouse tells us to do is avoid multiple costly round trips to any origin.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Avoid multiple, costly round trips to any origin&quot; decoding=&quot;async&quot; height=&quot;360&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GWsRfe3VEFOuHwgycWMS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 17.&lt;/strong&gt; Avoid multiple, costly round trips to any origin
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the case of the Oodle app, we’re actually heavily using Google Fonts. Whenever you drop a
Google Font stylesheet into your page it&#39;s going to connect up to two subdomains. And what
Lighthouse is telling us is that if we were able to warm up that connection, we could save
anywhere up to 300 milliseconds in our initial connection time.&lt;/p&gt;
&lt;p&gt;Taking advantage of link rel preconnect, we can effectively mask that connection latency.&lt;/p&gt;
&lt;p&gt;Especially with something like Google Fonts where our font face CSS is hosted
on &lt;a href=&quot;https://en.wikipedia.org/wiki/Google_APIs&quot; rel=&quot;noopener&quot;&gt;googleapis.com&lt;/a&gt;, and our font
resources are hosted on &lt;a href=&quot;https://superuser.com/a/64724&quot; rel=&quot;noopener&quot;&gt;Gstatic&lt;/a&gt;, this can have a really big
impact. So we applied this optimization and we shaved off a few hundred milliseconds.&lt;/p&gt;
&lt;p&gt;The next thing that Lighthouse suggests is that we preload key requests.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Preload key requests&quot; decoding=&quot;async&quot; height=&quot;366&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lt3Nvi9UtaejjVYHbGp9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 18.&lt;/strong&gt; Preload key requests
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;link rel=preload&amp;gt;&lt;/code&gt; is really powerful, it informs the browser that a resource is needed as
part of the current navigation, and it tries to get the browser fetching it as soon as possible.&lt;/p&gt;
&lt;p&gt;Now here Lighthouse is telling us that we should be going and preloading our key web font
resources, because we&#39;re loading in two web fonts.&lt;/p&gt;
&lt;p&gt;Preloading in a web font looks like this - specifying &lt;code&gt;rel=preload&lt;/code&gt;, you pass in &lt;code&gt;as&lt;/code&gt; with
the type of font, and then you specify the type of font you&#39;re trying to load in, such as woff2.&lt;/p&gt;
&lt;p&gt;The impact this can have on your page is quite stark.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Impact of preloading resources&quot; decoding=&quot;async&quot; height=&quot;326&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 585px) 585px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jDWc5PChSWiCbVZKlMDt.png?auto=format&amp;w=1170 1170w&quot; width=&quot;585&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 19.&lt;/strong&gt; Impact of preloading resources
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Normally, without using link rel preload, if web fonts happen to be critical to your page, what
the browser has to do is it first of all has to fetch your HTML, has to parse your CSS, and
somewhere much later down the line, it&#39;ll finally go and fetch your web fonts.&lt;/p&gt;
&lt;p&gt;Using link rel preload, as soon as the browser has parsed your HTML it can actually start fetching
those web fonts much earlier on. In the case of our app, this was able to shave a second off the
time it took for us to render text using our web fonts.&lt;/p&gt;
&lt;p&gt;Now it&#39;s not quite that straightforward if you&#39;re going to try preloading fonts using Google Fonts,
there is one gotcha.&lt;/p&gt;
&lt;p&gt;The Google Font URLs that we specify on our font faces in our stylesheets happened to be something
that the fonts team update fairly regularly. These URLs can expire, or get updated on a regular
frequency, and so what we would suggest to do if you want complete control over your font loading
experience is to self-host your web fonts. This can be great because it gives you access
to things like link rel preload.&lt;/p&gt;
&lt;p&gt;In our case we found the tool
&lt;a href=&quot;https://google-webfonts-helper.herokuapp.com/fonts&quot; rel=&quot;noopener&quot;&gt;Google Web Fonts Helper&lt;/a&gt;
really useful in helping us offline some of those web fonts and set them up locally, so check that
tool out.&lt;/p&gt;
&lt;p&gt;Whether you&#39;re using web fonts as part of your critical resources, or it happens to be JavaScript,
try to help the browser deliver your critical resources as soon as possible.&lt;/p&gt;
&lt;h3 id=&quot;experimental-priority-hints&quot;&gt;Experimental: Priority Hints &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#experimental-priority-hints&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ve got something special to share with you today. In addition to features like resource hints,
as well as preload, we&#39;ve been working on a brand new experimental browser feature we’re calling
priority hints.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Set priority for the initially visible content&quot; decoding=&quot;async&quot; height=&quot;326&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 585px) 585px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/jx7YvykNpmjO39vsrST5.png?auto=format&amp;w=1170 1170w&quot; width=&quot;585&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 20.&lt;/strong&gt; Priority hints
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is a new feature that allows you to hint to the browser how important a resource is. It
exposes a new attribute - importance - with the values low, high or auto.&lt;/p&gt;
&lt;p&gt;This allows us to convey lowering the priority of less important resources, such as non-critical
styles, images, or fetch API calls to reduce contention. We can also boost the priority of more
important things, like our hero images.&lt;/p&gt;
&lt;p&gt;In the case of our Oodle app, this actually led to one practical place where we could optimize.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Set priority for the initially visible content&quot; decoding=&quot;async&quot; height=&quot;334&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 587px) 587px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/IZtNqC7SDTVYQol6OOTF.png?auto=format&amp;w=1174 1174w&quot; width=&quot;587&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 21.&lt;/strong&gt; Set priority for the initially visible content
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Before we added lazy loading to our images, what the browser was doing is, we had this image
carousel with all of our doodles and the browser was fetching all the images at the very start
of the carousel with a high priority early on. Unfortunately, it was the images in the middle
of the carousel that were most important to the user. So what we did was, we set the importance
of those background images to very low, the foreground ones to very high, and what this had was
a two second impact over slow 3G, and how quickly we were able to fetch and render those images.
So a nice positive experience.&lt;/p&gt;
&lt;p&gt;We&#39;re hoping to bring this feature to &lt;a href=&quot;https://www.google.com/chrome/browser/canary.html&quot; rel=&quot;noopener&quot;&gt;Canary&lt;/a&gt;
in a few weeks, so keep an eye out for that.&lt;/p&gt;
&lt;h3 id=&quot;have-a-web-font-loading-strategy&quot;&gt;Have a web font loading strategy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#have-a-web-font-loading-strategy&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Typography is fundamental to good design, and if you&#39;re using web fonts you ideally don&#39;t want to
block rendering of your text, and you definitely don&#39;t want to show invisible text.&lt;/p&gt;
&lt;p&gt;We highlight this in Lighthouse now, with the &lt;strong&gt;avoid invisible text while web fonts are loading&lt;/strong&gt;
audit.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Avoid invisible text while Web Fonts are loading&quot; decoding=&quot;async&quot; height=&quot;400&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CamYoLwwQHGXmDyBXIr1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 22.&lt;/strong&gt; Avoid invisible text while Web Fonts are loading
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you load your web fonts using a font face block, you&#39;re letting the browser decide what to do
if it takes a long time for that web font to fetch. Some browsers will wait anywhere up
to three seconds for this before falling back to a system font, and they&#39;ll eventually swap it
out to the font once it&#39;s downloaded.&lt;/p&gt;
&lt;p&gt;We&#39;re trying to avoid this invisible text, so in this case we wouldn&#39;t have been able to see this
week&#39;s classic doodles if the web font had taken too long. Thankfully, with a new feature called
&lt;code&gt;font-display&lt;/code&gt;, you actually get a lot more control over this process.&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;@font-face&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Montserrat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;font-style&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;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; swap&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; 400&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Montserrat Regular&#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;local&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Montserrat-Regular&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token comment&quot;&gt;/* Chrome 26+, Opera 23+, Firefox 39+ */&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&#39;montserrat-v12-latin-regular.woff2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;woff2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&#39;montserrat-v12-latin-regular.woff&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;woff&#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;Font display helps you decide how web fonts will render or fallback based on how long it takes
for them to swap.&lt;/p&gt;
&lt;p&gt;In this case we&#39;re using font display swap. Swap gives the font face a zero second block period,
and an infinite swap period. This means the browser&#39;s going to draw your text pretty immediately
with a fallback font if the font takes a while to load. And it&#39;s going to swap it once the font
face is available.&lt;/p&gt;
&lt;p&gt;In the case of our app, why this was great is that it allowed us to display some meaningful text
very early on, and transition over to the web font once it was ready.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Font display outcome&quot; decoding=&quot;async&quot; height=&quot;331&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 585px) 585px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/54dx67WBnfcKzjduM4HT.png?auto=format&amp;w=1170 1170w&quot; width=&quot;585&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 23.&lt;/strong&gt; Font display outcome
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In general, if you happen to be using web fonts, as a large percentage of the web does, have
a good web font loading strategy in place.&lt;/p&gt;
&lt;p&gt;There are a lot of web platform features you can use to optimize your loading experience for fonts,
but also check out Zach Leatherman&#39;s &lt;a href=&quot;https://www.zachleat.com/web/recipes/&quot; rel=&quot;noopener&quot;&gt;Web Font Recipes repo&lt;/a&gt;,
because it&#39;s really great.&lt;/p&gt;
&lt;h3 id=&quot;reduce-render-blocking-scripts&quot;&gt;Reduce render-blocking scripts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#reduce-render-blocking-scripts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are other parts of our application that we could push earlier in the download chain to provide
at least some basic user experience a little bit earlier.&lt;/p&gt;
&lt;p&gt;On the Lighthouse timeline strip you can see that during these first few seconds when all the
resources are loading, the user cannot really see any content.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Reduce render-blocking stylesheets opportunity&quot; decoding=&quot;async&quot; height=&quot;259&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HX1xfdh4LrEeUrMJWWYc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 24.&lt;/strong&gt; Reduce render-blocking stylesheets opportunity
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Downloading and processing external stylesheets is blocking our rendering process from making
any progress.&lt;/p&gt;
&lt;p&gt;We can try to optimize our critical rendering path by delivering some of the styles a bit earlier.&lt;/p&gt;
&lt;p&gt;If we extract the styles that are responsible for this initial render and inline them in our HTML,
the browser is able to render them straight away without waiting for the external stylesheets
to arrive.&lt;/p&gt;
&lt;p&gt;In our case, we used an NPM module called &lt;a href=&quot;https://www.npmjs.com/package/critical&quot; rel=&quot;noopener&quot;&gt;Critical&lt;/a&gt;
to inline our critical content in index.html during a build step.&lt;/p&gt;
&lt;p&gt;While this module did most of the heavy lifting for us, it was still a little bit tricky to get
this working smoothly across different routes.&lt;/p&gt;
&lt;p&gt;If you are not careful or your site structure is really complex, it might be really difficult to
introduce this type of pattern if you did not plan for
&lt;a href=&quot;https://web.dev/learn/pwa/architecture/&quot;&gt;app shell architecture&lt;/a&gt;
from the beginning.&lt;/p&gt;
&lt;p&gt;This is why it&#39;s so important to take performance considerations early on. If you don&#39;t design for
performance from the start, there is a high chance that you will you run into issues doing it later.&lt;/p&gt;
&lt;p&gt;In the end our risk paid off, we managed to make it work and the app started delivering content much
earlier, improving our first meaningful paint time significantly.&lt;/p&gt;
&lt;h2 id=&quot;the-outcome&quot;&gt;The outcome &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#the-outcome&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That was a long list of performance optimizations we applied to our site. Let&#39;s take a look at the
outcome. This is how our app loaded on a medium mobile device on a 3G network, before and after
the optimization.&lt;/p&gt;
&lt;figure&gt;
  &lt;video&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/T4FyVKpzu4WKF1kBNvXepbi08t52/rGDjStPqX0zUn0X2D52W.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;The Lighthouse performance score went up from 23 to 91. That&#39;s pretty nice progress in terms
of speed. All of the changes were fueled by us continuously checking and following the Lighthouse
report. If you&#39;d like to check out how we technically implemented all of the improvements, feel
free to take a look at &lt;a href=&quot;http://github.com/google/oodle-demo&quot; rel=&quot;noopener&quot;&gt;our repo&lt;/a&gt;, especially at the PRs that
landed there.&lt;/p&gt;
&lt;h2 id=&quot;predictive-performance-data-driven-user-experiences&quot;&gt;Predictive performance  - data-driven user experiences &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#predictive-performance-data-driven-user-experiences&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We believe that machine learning represents an exciting opportunity for the future in many areas.
One idea that we hope will spark more experimentation in the future, is that real data can really
guide the user experiences we’re creating.&lt;/p&gt;
&lt;p&gt;Today, we make a lot of arbitrary decisions about what the user might want or need, and therefore
what is worth being prefetched, or preloaded, or pre-cached. If we guess right we are able to
prioritize a small amount of resources, but it&#39;s really hard to scale it to the whole website.&lt;/p&gt;
&lt;p&gt;We actually have data available to better inform our optimizations today.
Using the &lt;a href=&quot;https://developers.google.com/analytics/devguides/reporting/core/v4/&quot; rel=&quot;noopener&quot;&gt;Google Analytics reporting API&lt;/a&gt;
we can take a look at the next top page and exit
percentages for any URL on our site and therefore drive conclusions on which resources we should
prioritize.&lt;/p&gt;
&lt;p&gt;If we combine this with a good probability model, we avoid wasting our user’s data by aggressively
over-prefetching content. We can take advantage of that Google
Analytics data, and use machine learning and models like
&lt;a href=&quot;https://en.wikipedia.org/wiki/Markov_chain&quot; rel=&quot;noopener&quot;&gt;Markov chains&lt;/a&gt; or
&lt;a href=&quot;https://en.wikipedia.org/wiki/Artificial_neural_network&quot; rel=&quot;noopener&quot;&gt;neural network&lt;/a&gt; in order
to implement such models.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Data-driven Bundling for Web Apps&quot; decoding=&quot;async&quot; height=&quot;348&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eNZRHsxXBbFLRFSz3HOq.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 25.&lt;/strong&gt; Data-driven Bundling for Web Apps
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In order to facilitate this experiments, we&#39;re happy to announce a new initiative we&#39;re calling
&lt;a href=&quot;https://github.com/guess-js/guess&quot; rel=&quot;noopener&quot;&gt;Guess.js&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Guess.js&quot; decoding=&quot;async&quot; height=&quot;324&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 584px) 584px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/zRGcCvp2LeX0aPebJK7K.png?auto=format&amp;w=1168 1168w&quot; width=&quot;584&quot; /&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Fig. 26.&lt;/strong&gt; Guess.js
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Guess.js is a project focused on data-driven user experiences for the web. We hope that it&#39;s going
to inspire exploration of using data to improve web performance and go beyond that. It&#39;s all
open source and available on GitHub today. This was built in collaboration with the open source
community by Minko Gechev, Kyle Matthews from Gatsby, Katie Hempenius, and a number of others.&lt;/p&gt;
&lt;p&gt;Check out Guess.js, let us know what you think.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-performance-made-easy/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Scores and metrics are helpful in improving speed of the Web, but they are just the means,
not the goals themselves.&lt;/p&gt;
&lt;p&gt;We&#39;ve all experienced slow page loads on the go, but we now have an opportunity to give our
users more delightful experiences that load really quickly.&lt;/p&gt;
&lt;p&gt;Improving performance is a journey. Lots of small changes can lead to big gains. By using the
right optimization tools and keeping an eye on the Lighthouse reports, you can provide better
and more inclusive experience to your users.&lt;/p&gt;
&lt;p&gt;With special thanks to: Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino,
Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse &amp;amp; Google Doodles.&lt;/p&gt;
</content>
    <author>
      <name>Ewa Gasperowicz</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Loading Third-Party JavaScript</title>
    <link href="https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/"/>
    <updated>2018-02-28T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/</id>
    <content type="html" mode="escaped">&lt;p&gt;You&#39;ve optimized all of your code, but your site still loads too slowly. Who&#39;s
the culprit?&lt;/p&gt;
&lt;p&gt;Often, performance problems slowing pages down are due to third-party scripts:
ads, analytics, trackers, social media buttons, and so on.&lt;/p&gt;
&lt;p&gt;Third-party scripts provide a wide range of useful functionality, making the web
more dynamic, interactive, and interconnected. These scripts may be crucial to
your website&#39;s functionality or revenue stream. But third-party scripts also
come with &lt;strong&gt;many risks&lt;/strong&gt; that should be taken into consideration to &lt;strong&gt;minimize their impact&lt;/strong&gt; while still providing value.&lt;/p&gt;
&lt;p&gt;Why do you need to be
&lt;a href=&quot;https://css-tricks.com/potential-dangers-of-third-party-javascript/&quot; rel=&quot;noopener&quot;&gt;careful&lt;/a&gt;
about third-party scripts?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They can be a &lt;strong&gt;performance&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They can be a &lt;strong&gt;privacy&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They might be a &lt;strong&gt;security&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They can be &lt;strong&gt;unpredictable&lt;/strong&gt; and change without you knowing&lt;/li&gt;
&lt;li&gt;They can have &lt;strong&gt;unintended consequences&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideally, you’ll want to ensure third-party script is not impacting the &lt;a href=&quot;https://web.dev/critical-rendering-path/&quot;&gt;critical rendering path&lt;/a&gt;. In this
guide, we’ll walk through how to find and fix issues related to loading
third-party JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-mean-by-third-party-scripts&quot;&gt;What do we mean by third-party scripts? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#what-do-we-mean-by-third-party-scripts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Third-party JavaScript often refers to scripts that can be embedded into any
site directly from a third-party vendor. These scripts can include ads,
analytics, widgets and other scripts that make the web more dynamic and
interactive.&lt;/p&gt;
&lt;p&gt;Examples of third-party scripts include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Social sharing buttons (Twitter, Facebook, G+)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Video player embeds (YouTube, Vimeo)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Advertising iframes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Analytics &amp;amp; metrics scripts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A/B testing scripts for experiments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Helper libraries (such as date formatting, animation, or functional libraries)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;example of a youtube video embed&quot; decoding=&quot;async&quot; height=&quot;267&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;iframe&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;560&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;315&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/mo8thg5XGV0&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;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;autoplay; encrypted-media&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;allowfullscreen&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;iframe&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;One example of this is the YouTube video player embed script that allows you to
embed a video into your page.&lt;/p&gt;
&lt;p&gt;Unfortunately, embedding third-party scripts means we often rely on them to be
fast in order to avoid slowing our pages down. Third-party scripts are a
predominant cause of performance slowdowns and are often caused by resources
outside of your control.&lt;/p&gt;
&lt;p&gt;These issues can include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Firing too many network requests to multiple servers. The more requests a site
has to make, the longer it can take to load.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sending &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time/&quot; rel=&quot;noopener&quot;&gt;too much JavaScript&lt;/a&gt;
that keeps the main thread busy. Too much JavaScript can block DOM
construction, delaying how quickly pages can render. CPU-intensive script
parsing and execution can delay user interaction and cause battery drain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sending large, &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-optimized-images/&quot; rel=&quot;noopener&quot;&gt;unoptimized image files&lt;/a&gt; or videos. This can
consume data and cost users money.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third-party scripts loaded without care can be a &lt;a href=&quot;http://blog.patrickmeenan.com/2011/10/testing-for-frontend-spof.html&quot; rel=&quot;noopener&quot;&gt;single-point of failure&lt;/a&gt;
(SPOF)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insufficient &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;HTTP caching&lt;/a&gt;,
forcing resources to be fetched from the network often&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of sufficient &lt;a href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/&quot;&gt;server compression&lt;/a&gt;
of resources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blocking content display until they complete processing. This can also be true
for async A/B testing scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use of legacy APIs (e.g &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/no-document-write/&quot; rel=&quot;noopener&quot;&gt;document.write()&lt;/a&gt;) known to be harmful to the user experience&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Excessive DOM elements or expensive CSS selectors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Including multiple third-party embeds can lead to multiple frameworks and
libraries being pulled in several times. This is wasteful and exacerbates the
performance issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third-party scripts often use embed techniques that can block
&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/API/GlobalEventHandlers/onload&quot; rel=&quot;noopener&quot;&gt;window.onload&lt;/a&gt;
if their servers respond slowly, even if the embed is using async or defer.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Context is important and the solution to costly third-parties can depend on your
site and your ability to configure how you load third-party code. Thankfully, a
number of solutions and tools exist to find and fix issues with third-party
resources.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-identify-third-party-script-on-a-page&quot;&gt;How do you identify third-party script on a page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-you-identify-third-party-script-on-a-page&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unless you’re aware which third-party scripts are loaded by your site and what
their performance impact is, it’s impossible to know how to optimize them. Many
free web speed test tools can highlight costly third-parties including &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt;, &lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; and
&lt;a href=&quot;https://www.webpagetest.org/&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt;. These tools display rich diagnostic
information that can tell you &lt;em&gt;how many&lt;/em&gt; third-party scripts your
site is loading, and which take the most time to execute.&lt;/p&gt;
&lt;p&gt;WebPageTest’s waterfall view can highlight the impact of heavy third-party
script use. Below is an example of the requests required to load the main
content for a site vs. the tracking and marketing scripts (credit: &lt;a href=&quot;https://nystudio107.com/blog/tags-gone-wild&quot; rel=&quot;noopener&quot;&gt;Tags Gone Wild&lt;/a&gt;).&lt;/p&gt;
&lt;img alt=&quot;waterfall view from webpagetest showing an actual website vs the amount of time spent loading tracking scripts&quot; decoding=&quot;async&quot; height=&quot;983&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;WebPageTest’s &lt;a href=&quot;https://www.google.com/url?q=https://www.webpagetest.org/result/180222_J4_8fee6855d6f45719e4f37d8d89ecbc20/1/domains/&amp;amp;sa=D&amp;amp;ust=1519325015196000&amp;amp;usg=AFQjCNGrRivilJS9yqqpombsUMQZQJx2nw&quot; rel=&quot;noopener&quot;&gt;domain breakdown&lt;/a&gt;
can also be useful for visualizing how much content comes from third-party
origins. It breaks this down by both total bytes and the number of requests:&lt;/p&gt;
&lt;img alt=&quot;content breakdown by domain (first view). Shows the percentage of requests and bytes for each third-party&quot; decoding=&quot;async&quot; height=&quot;456&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;When you see a problematic script, figure out what the script does and ask
yourself whether the script is really that necessary. Do an A/B test to balance
the perceived value versus its impact on key user engagement or performance
metrics.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-measure-the-impact-of-third-party-script-on-my-page&quot;&gt;How do I measure the impact of third-party script on my page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-i-measure-the-impact-of-third-party-script-on-my-page&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;lighthouse-boot-up-time-audit&quot;&gt;Lighthouse Boot-up Time Audit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lighthouse-boot-up-time-audit&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Lighthouse &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time/&quot; rel=&quot;noopener&quot;&gt;JavaScript boot-up time audit&lt;/a&gt; highlights scripts that have a
costly script parse, compile or evaluation time. This can be useful for
discovering CPU-intensive third-party scripts.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse showing support for script evaluating and parsing&quot; decoding=&quot;async&quot; height=&quot;523&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;lighthouse-network-payloads-audit&quot;&gt;Lighthouse Network Payloads Audit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lighthouse-network-payloads-audit&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Lighthouse &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/total-byte-weight/&quot; rel=&quot;noopener&quot;&gt;Network Payloads audit&lt;/a&gt; identifies network
requests (including those from third-parties) that may slow down page load time.
Avoiding these requests or highlighting their cost to ad-networks can save users
money they would have spent on cellular data.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse showing support for large network payloads&quot; decoding=&quot;async&quot; height=&quot;477&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;chrome-devtools-network-request-blocking&quot;&gt;Chrome DevTools Network Request Blocking &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#chrome-devtools-network-request-blocking&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome DevTools allows you to see how your page behaves when a particular
script, stylesheet or other resource isn’t available. This is done with &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-59/#block-requests&quot; rel=&quot;noopener&quot;&gt;network request blocking&lt;/a&gt;, a
feature that can help measure the impact of blocking (dropping) specific
third-party resources from your page.&lt;/p&gt;
&lt;p&gt;To enable request blocking, right click on any request in the Network panel and
select &amp;quot;Block Request URL&amp;quot;. A Request blocking tab will display in the DevTools
drawer, letting you manage which requests have been blocked.&lt;/p&gt;
&lt;img alt=&quot;Block request URLs from the DevTools network panel&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/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;chrome-devtools-performance-panel&quot;&gt;Chrome DevTools Performance Panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#chrome-devtools-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/reference/&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt; in Chrome
DevTools helps identify issues with your page’s web performance. Clicking the
record button and loading your page presents you with a waterfall representing
where your site is spending time. At the bottom of the Performance panel, you
will see a drawer starting with
&amp;quot;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/reference/#record-load&quot; rel=&quot;noopener&quot;&gt;Summary&lt;/a&gt;&amp;quot;.
Navigate to the “Bottom-up” tab.&lt;/p&gt;
&lt;p&gt;Here, you can use the &amp;quot;Group by product&amp;quot; option in the Bottom-Up tab to group
third-parties by the time they spent. This helps identify which third-party
products were the most costly. The &lt;a href=&quot;https://umaar.com/dev-tips/143-network-products/&quot; rel=&quot;noopener&quot;&gt;Network panel&lt;/a&gt; also supports an option
to highlight requests by product.&lt;/p&gt;
&lt;img alt=&quot;DevTools Performance panel showing the Bottom-up view grouped by (third-party) products&quot; decoding=&quot;async&quot; height=&quot;744&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To learn more about how to analyze page load performance with the Chrome
DevTools, see &lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/&quot; rel=&quot;noopener&quot;&gt;Get started with analyzing runtime performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A good &lt;strong&gt;workflow&lt;/strong&gt; for measuring the impact of third-party scripts is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Measure how long it takes to load your page using the Network panel.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To emulate real-world conditions, we recommend turning on &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/reference/#throttling&quot; rel=&quot;noopener&quot;&gt;network throttling&lt;/a&gt; and
&lt;a href=&quot;https://developer.chrome.com/docs/devtools/device-mode/#cpu&quot; rel=&quot;noopener&quot;&gt;CPU throttling&lt;/a&gt;.
On faster connections and desktop hardware, the impact of expensive
scripts may not be as representative as it would on a mobile phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Block the URLs or domains responsible for third-party scripts you believe are
an issue (see &lt;em&gt;Chrome DevTools Performance Panel&lt;/em&gt; for identifying costly
scripts).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload the page and re-measure how long the page takes without loading these
blocked third-party scripts. You should hopefully see an improvement.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There may be value in doing 3 or more runs of measurement and looking at
the median for more stable figures. As third-party content can
occasionally pull in different resources per page load, this could give
you a more realistic spread. &lt;a href=&quot;https://twitter.com/ChromeDevTools/status/963820146388221952&quot; rel=&quot;noopener&quot;&gt;DevTools now supports multiple recordings&lt;/a&gt;
in the performance panel, making this a little easier.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;measuring-impact-of-third-party-tags-with-webpagetest&quot;&gt;Measuring impact of Third-Party tags with WebPageTest &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#measuring-impact-of-third-party-tags-with-webpagetest&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.webpagetest.org/&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt; supports blocking individual
requests from loading (which can be useful for blocking content like ads and
third-party embeds) to measure their impact.&lt;/p&gt;
&lt;p&gt;Under &amp;quot;Advanced Settings&amp;quot; is a Block tab. This can be used to specify a list of
domains to block, simulating what it would be like if they didn&#39;t load at all.&lt;/p&gt;
&lt;img alt=&quot;WebPageTest advanced settings &amp;amp;lt; Block. Displays a text area for specifying domains to block.&quot; decoding=&quot;async&quot; height=&quot;316&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;A workflow for using this feature is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Test a page as normal&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat the test with certain third-parties blocked&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare the two results (paying attention to the filmstrip). Results can be
compared by selecting them from your &lt;a href=&quot;https://www.webpagetest.org/testlog/1/&quot; rel=&quot;noopener&quot;&gt;Test History&lt;/a&gt; and clicking ‘Compare’.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;WebPageTest displaying the compare option allowing you to compare two reports&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/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Below we can see the difference between filmstrips both with and without
third-party resources blocked. It can be useful to try this out for individual
third-party origins to determine which ones have the biggest impact on your
page-load performance:&lt;/p&gt;
&lt;img alt=&quot;WebPageTest filmstrip displaying the impact of loading a site with and without third-parties disabled&quot; decoding=&quot;async&quot; height=&quot;139&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The impact of blocking third-party resources on a page using WPT’s &amp;quot;block
requests&amp;quot; feature from “&lt;a href=&quot;https://goo.gl/jwGg6X&quot; rel=&quot;noopener&quot;&gt;Using WebPageTest To Measure The Impact Of Third-Party Tags&lt;/a&gt;” by Andy Davies&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; WebPageTest also supports two commands operating at the DNS level for blocking domains. &lt;a href=&quot;https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/scripting#TOC-blockDomains&quot;&gt;blockDomains&lt;/a&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;which takes a list of domains to block and
&lt;a href=&quot;https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/scripting#TOC-blockDomainsExcept&quot; rel=&quot;noopener&quot;&gt;blockDomainsExcept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;takes a list of domains and blocks anything not on the list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WebPageTest also has a single-point of failure (SPOF) tab. This allows you to
simulate a timeout or complete failure to load a resource.&lt;/p&gt;
&lt;p&gt;The difference between &amp;quot;SPOF&amp;quot; and &amp;quot;Block&amp;quot; is that SPOF slowly times out. This
can make it useful for testing network resilience of third-party content to
determine how well your pages hold up when services are under heavy load or
temporarily unavailable.&lt;/p&gt;
&lt;img alt=&quot;WebPageTest advanced settings &amp;amp;gt; SPOF &amp;amp;gt; hosts to fail&quot; decoding=&quot;async&quot; height=&quot;346&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;detecting-expensive-iframes-using-long-tasks&quot;&gt;Detecting expensive iframes using Long Tasks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#detecting-expensive-iframes-using-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When scripts in third-party iframes take a long time to run, they can block the
main thread delaying other tasks from running. These long tasks can cause a
negative user experience leading to sluggish event handlers or dropped frames.&lt;/p&gt;
&lt;p&gt;To detect long tasks for &lt;a href=&quot;https://en.wikipedia.org/wiki/Real_user_monitoring&quot; rel=&quot;noopener&quot;&gt;Real User Monitoring&lt;/a&gt; (RUM), we can
use the JavaScript
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/PerformanceObserver&quot; rel=&quot;noopener&quot;&gt;PerformanceObserver&lt;/a&gt;
API and observe
&lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#custom-metrics&quot;&gt;longtask&lt;/a&gt;
entries. As these entries contain an attribution property, we can track down
which frame context was responsible for the task.&lt;/p&gt;
&lt;p&gt;Below is an example that will log &lt;code&gt;longtask&lt;/code&gt; entries to the console, including
one for an &amp;quot;expensive&amp;quot; iframe:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; observer &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;PerformanceObserver&lt;/span&gt;&lt;span class=&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;list&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;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entry &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// Attribution entry including &quot;containerSrc&quot;:&quot;https://example.com&quot;&lt;/span&gt;&lt;br /&gt;      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&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 class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;entryTypes&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;longtask&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Imagine this is an iframe with expensive long tasks --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To learn more about monitoring Long Tasks, read Phil Walton’s &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#custom-metrics&quot;&gt;User-centric Performance Metrics&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-load-third-party-script-efficiently&quot;&gt;How do you load third-party script efficiently? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-you-load-third-party-script-efficiently&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a third-party script is slowing down your page load, you have several options
to improve performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Load the script using the async or defer attribute to avoid blocking document
parsing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider self-hosting the script if the third-party server is slow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider removing the script if it doesn&#39;t add clear value to your site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;Resource Hints&lt;/a&gt; like
&lt;code&gt;&amp;lt;link rel=preconnect&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;link rel=dns-prefetch&amp;gt;&lt;/code&gt; to perform a DNS lookup
for domains hosting third-party scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;use-async-or-defer&quot;&gt;Use async or defer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-async-or-defer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript execution is parser blocking. This means when the browser encounters
a script it must pause DOM construction, hand this over to the JavaScript engine
and allow script execution before proceeding with DOM construction.&lt;/p&gt;
&lt;p&gt;The async and defer attributes change this behavior.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;With async, the browser downloads the script asynchronously while it continues
to parse the HTML document. When the script finishes downloading, parsing is
blocked while the script executes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With defer, the browser downloads the script asynchronously while it continues
to parse the HTML document. The script doesn&#39;t run until the parsing is
complete.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If that&#39;s too many words, here&#39;s a pretty picture:&lt;/p&gt;
&lt;img alt=&quot;A visualization comparing the impact of using script vs script async vs script defer. Defer is showing as executing after script fetch and HTML parsing is done.&quot; decoding=&quot;async&quot; height=&quot;447&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;Credit: Growing with the web&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In general, you should always use &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; for third-party scripts
(unless the script does something necessary for the critical rendering path):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;async&lt;/code&gt; if it&#39;s important to have the script run earlier in the loading
process. This might include some analytics scripts, for example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;defer&lt;/code&gt; for less critical resources. A video player that&#39;s below-the-fold,
for example.&lt;/p&gt;
&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; If performance is your primary concern, you could wait until your page has reached a key user moment (such as after the critical content has loaded) before adding async scripts. You should also take care not to &lt;code&gt;async&lt;/code&gt; load libraries like jQuery just because they are coming from a third-party CDN. &lt;/div&gt;&lt;/aside&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 Blink-based browsers, &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; currently &lt;a href=&quot;https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit#&quot;&gt;lower the priority of the network request&lt;/a&gt; for resources so it can cause it to load significantly later than it would as a blocking script. This is useful to know in particular for analytics scripts. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Should you ever load third-party scripts without &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;? You could
make a case for this if the script is a crucial part of your site functionality.
For example, if you&#39;re loading your main UI library or framework from a CDN, it
will be badged as &amp;quot;third-party script&amp;quot; in DevTools, but should be treated as an
essential part of your site, not an add-on.&lt;/p&gt;
&lt;p&gt;Note that not all scripts work if loaded asynchronously. Check the docs for any
third-party scripts you&#39;re using. If you&#39;re using a script that can&#39;t be loaded
asynchronously, you might want to consider an alternative, or eliminating the
script if possible. Some third parties may &lt;em&gt;highly recommend&lt;/em&gt; to load their
scripts sync (to get ahead of other scripts), even if they would work fine async
so do due diligence when evaluating strategies for loading third-party scripts.&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;code&gt;async&lt;/code&gt; is not a silver bullet. If a marketing team wants to load a large number of tracking scripts on a page, this number will still introduce bottlenecks that can impact how soon users can engage with a page on load. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;use-resource-hints-to-reduce-connection-setup-time&quot;&gt;Use Resource Hints to reduce connection setup time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-resource-hints-to-reduce-connection-setup-time&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Establishing connections to third-party origins can take a significant amount of
time - particularly on slow networks. Many steps can add up to delays including
DNS lookups, redirects, and potentially several round trips to each third-party
server to handle the request.&lt;/p&gt;
&lt;p&gt;You can use &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;Resource Hints&lt;/a&gt; like
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/#improve-page-load-speed-with-preconnect&quot; rel=&quot;noopener&quot;&gt;&lt;link rel=&quot;dns-prefetch&quot; /&gt;&lt;/a&gt;
to perform a DNS lookup for domains hosting third-party scripts. When the
request for them is finally made, time can be saved as the DNS lookup has
already been carried out.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dns-prefetch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If the third-party domain you are referencing uses HTTPS, you may also consider
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;&lt;link rel=&quot;preconnect&quot; /&gt;&lt;/a&gt;
as this will both perform the DNS lookup &lt;em&gt;and&lt;/em&gt; resolve TCP round-trips and
handle TLS negotiations. These other steps can be very slow as they involve
looking at SSL certificates for verification, so consider Resource Hints
seriously if you find third-party setup time to be an issue.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preconnect&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;sandbox-scripts-with-an-iframe&quot;&gt;&amp;quot;Sandbox&amp;quot; scripts with an iframe &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#sandbox-scripts-with-an-iframe&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are cases where third-party scripts can be loaded directly into an iframe.
By restricting such scripts to iframes, they won’t block execution of the main
page. This is the same approach that
&lt;a href=&quot;https://www.ampproject.org/learn/about-how/&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt; takes to keeping JavaScript
out of the &lt;a href=&quot;https://web.dev/critical-rendering-path/&quot;&gt;critical path&lt;/a&gt;. Note that this
approach will still block the &lt;code&gt;onload&lt;/code&gt; event so try not to attach critical
functionality to &lt;code&gt;onload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Chrome also supports &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Permissions_Policy&quot; rel=&quot;noopener&quot;&gt;Permissions Policy&lt;/a&gt;
(formerly Feature Policy) - a set of policies which allow a developer to selectively disable access to certain browser
features. This can prevent third-party content introducing unwanted behaviors to a site.&lt;/p&gt;
&lt;h3 id=&quot;self-host-third-party-scripts&quot;&gt;Self-host third-party scripts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#self-host-third-party-scripts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Self-hosting third-party scripts may be an option if you would like more control
over a script’s loading story. For example, if you wanted to reduce DNS or
round-trip times, or improve HTTP caching headers. Self-hosting may be a viable
consideration if a script is considered critical.&lt;/p&gt;
&lt;p&gt;Self-hosting can come with a number of big caveats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Scripts can go out of date. This can be a large issue as it prevents you from
getting important security fixes without manually updating.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scripts that are self-hosted won’t get automatic updates due to an API change.
One example: a publisher with 90% of their revenue from ads discovers that ads
didn’t serve for half a day due to an API change that their self-hosted script
didn’t account for, leading to loss in income.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An alternative to self-hosting scripts would be using &lt;a href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview/&quot; rel=&quot;noopener&quot;&gt;Service Workers&lt;/a&gt; to cache them. This can
give you greater control over how often they are re-fetched from the network.
This could also be used to create a loading strategy where requests for
non-essential third parties are throttled until the page reaches a key user
moment.&lt;/p&gt;
&lt;h3 id=&quot;ab-test-smaller-samples-of-users&quot;&gt;A/B Test smaller samples of users &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#ab-test-smaller-samples-of-users&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.optimizely.com/optimization-glossary/ab-testing/&quot; rel=&quot;noopener&quot;&gt;A/B testing&lt;/a&gt; (or
split-testing) is a technique for experimenting with two versions of a page to
determine which one performs best. This is done by enabling both variants (A and
B) for different samples of your website traffic. The page that provides a
better conversion rate wins.&lt;/p&gt;
&lt;p&gt;A/B testing is a very useful tool for analyzing user experience and behavior.&lt;/p&gt;
&lt;p&gt;However, by design, A/B testing delays rendering to figure out which experiment
needs to be active. JavaScript is often used to check if any of your users
belong to an A/B test experiment and then enable the correct variant. This
pattern can lead to 100% of your users being sent down large, costly script even
if they don’t belong to the sample receiving the experiment.&lt;/p&gt;
&lt;p&gt;A good alternative in this case is to send A/B testing scripts for only a subset
of your user base (e.g 10% vs 100%), ideally attempting to decide whether they
belong in a test sample on the server-side. This improves the loading experience
for the majority of users while still making split-testing possible.&lt;/p&gt;
&lt;h3 id=&quot;lazy-load-third-party-resources&quot;&gt;Lazy load Third-Party Resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lazy-load-third-party-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Embedded third-party resources (such as ads or videos) can be a big contributor
to slow page speed when constructed poorly. Lazy loading can be used to only
load embedded resources when necessary. For example, serving an ad in the footer
only when a user scrolls down the page. Another pattern is lazy loading content
after the main page content loads but before a user might otherwise interact
with the page.&lt;/p&gt;
&lt;img alt=&quot;An illustration showing assets that are critical for the above the fold experience and those that are less critical and can be lazily loaded in.&quot; decoding=&quot;async&quot; height=&quot;340&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 767px) 767px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1534 1534w&quot; width=&quot;767&quot; /&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://github.com/aFarkas/lazysizes&quot;&gt;LazySizes&lt;/a&gt; is a popular JavaScript library for lazy loading images and&lt;a href=&quot;http://afarkas.github.io/lazysizes/#examples&quot;&gt;iframes&lt;/a&gt;. It supports YouTube embeds and&lt;a href=&quot;https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/unveilhooks&quot;&gt;widgets&lt;/a&gt;. Care does need to be taken when lazy loading any resources as this technique is often powered by JavaScript and can be subject to issues on flaky network connections. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;DoubleClick have guidance on how to lazy-load ads in their &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4578089#lazyloading&quot; rel=&quot;noopener&quot;&gt;official documentation&lt;/a&gt;.
If used properly, lazy loading can increase the overall viewability percentage
of an ad. For example, Mediavine switched to&lt;a href=&quot;https://www.mediavine.com/lazy-loading-ads-mediavine-ads-load-200-faster/&quot; rel=&quot;noopener&quot;&gt;lazy-loading ads&lt;/a&gt;
and saw a 200% improvement in page load speed.&lt;/p&gt;
&lt;h4 id=&quot;efficient-lazy-loading-with-intersection-observer&quot;&gt;Efficient lazy loading with Intersection Observer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#efficient-lazy-loading-with-intersection-observer&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Historically, solutions for detecting if an element is visible in the viewport
(in order to lazy-load its content) have been error-prone, often causing the
browser to become sluggish. Solutions have often listened for
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Events/scroll&quot; rel=&quot;noopener&quot;&gt;scroll&lt;/a&gt; or
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Events/resize&quot; rel=&quot;noopener&quot;&gt;resize&lt;/a&gt; events,
then used DOM APIs like
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Element/getBoundingClientRect&quot; rel=&quot;noopener&quot;&gt;getBoundingClientRect()&lt;/a&gt;
to calculate where elements are relative to the viewport. This works, but is not
efficient.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/intersectionobserver-v2/&quot;&gt;IntersectionObserver&lt;/a&gt; is a browser
API that allows us to efficiently detect when an observed element enters or
exits the browser&#39;s viewport. Learn more about how to use it for &lt;a href=&quot;https://deanhume.com/home/blogpost/lazy-loading-images-using-intersection-observer/10163&quot; rel=&quot;noopener&quot;&gt;lazy loading resources&lt;/a&gt;.
LazySizes also has&lt;a href=&quot;https://github.com/aFarkas/lazysizes/blob/097a9878817dd17be3366633e555f3929a7eaaf1/src/lazysizes-intersection.js&quot; rel=&quot;noopener&quot;&gt;optional support&lt;/a&gt;
for IntersectionObserver.&lt;/p&gt;
&lt;h3 id=&quot;analytics-can-be-complicated&quot;&gt;Analytics can be complicated &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#analytics-can-be-complicated&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Analytics scripts should never slow down your page load experience, but if you
defer the load too long you can miss valuable analytics data. Fortunately, there
are some well-known patterns for initializing analytics lazily while retaining
early page-load data.&lt;/p&gt;
&lt;p&gt;Phil Walton&#39;s blog post, &lt;a href=&quot;https://philipwalton.com/articles/the-google-analytics-setup-i-use-on-every-site-i-build/&quot; rel=&quot;noopener&quot;&gt;The Google Analytics Setup I Use on Every Site I Build&lt;/a&gt;
covers one such pattern for Google Analytics.&lt;/p&gt;
&lt;h2 id=&quot;what-patterns-should-i-avoid-with-third-party-script&quot;&gt;What patterns should I avoid with third-party script? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#what-patterns-should-i-avoid-with-third-party-script&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;avoid-documentwrite&quot;&gt;Avoid document.write() &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#avoid-documentwrite&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Third-party scripts sometimes use
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Document/write&quot; rel=&quot;noopener&quot;&gt;document.write()&lt;/a&gt;
to inject and load scripts. This is particularly true of older services that
haven’t been updated in some time. Thankfully, many third-parties offer an
option to asynchronously load themselves, which allows third-party scripts to
load without blocking the display of the rest of the content on the page.&lt;/p&gt;
&lt;p&gt;The fix for document.write() is to simply not inject scripts using it. As of
Chrome 53, Chrome DevTools will log warnings to the console for problematic use
of document.write():&lt;/p&gt;
&lt;img alt=&quot;DevTools console warnings highlighting violations for a third-party embed using document.write()&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To discover the use of document.write() at scale, you can check for &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers&quot; rel=&quot;noopener&quot;&gt;HTTP headers&lt;/a&gt; sent to your
browser when this intervention for Chrome happens.
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; can also highlight any third-party scripts
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/no-document-write/&quot; rel=&quot;noopener&quot;&gt;still using document.write()&lt;/a&gt; in
the Lighthouse report:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse Best Practices audit flagging use of document.write()&quot; decoding=&quot;async&quot; height=&quot;438&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;use-tag-managers-but-use-them-wisely&quot;&gt;Use Tag Managers but use them wisely &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-tag-managers-but-use-them-wisely&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Exercise caution when using GTM. Although it can minimize the overhead of third-party tags, it also makes it trivial for anyone with credentials to add costly tags. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;A &amp;quot;tag&amp;quot; is a snippet of code that allows digital marketing teams to collect
data, set cookies or integrate third-party content like social media widgets
into a site. These tags have a cost to your page&#39;s loading performance -
additional network requests, heavy JavaScript dependencies, images and resources
the tag itself may pull in.&lt;/p&gt;
&lt;p&gt;Managing these tags can become a real mess over time as marketing teams wish to
add more ways to understand users and engineering tries to minimize the impact
tags can have on user experience. To keep experiences fast, we recommend using a
Tag manager. Tag managers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;allow many pieces of third-party embed code to be managed from a single place
(usually a user-interface)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;attempt to minimize how much third-party tags need to be deployed to sites.&lt;/p&gt;
&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; Even though individual tags can be asynchronously loaded, they still need to be read and executed individually. This could mean requesting more data while the page is still loading. Tag managers address this by reducing the number of calls a browser needs to make for them down to one. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/analytics/tag-manager/&quot; rel=&quot;noopener&quot;&gt;Google Tag Manager&lt;/a&gt; (GTM) is one
such popular tag manager:&lt;/p&gt;
&lt;p&gt;&amp;quot;Google Tag Manager is an asynchronous tag, meaning that when it executes, it
does not block other elements from rendering on the page. It also causes the
other tags that are deployed via Google Tag Manager to be deployed
asynchronously, meaning that a slow loading tag won’t block other tracking
tags.&amp;quot;&lt;/p&gt;
&lt;p&gt;Tag managers may improve page load performance by reducing how many calls to
external resources are needed - as long as you &lt;strong&gt;are not&lt;/strong&gt; pulling in a large
number of tags. They also allow tags a way to collect values in a single unique
place. For GTM, this is the &lt;a href=&quot;https://developers.google.com/tag-platform/tag-manager/web/datalayer&quot; rel=&quot;noopener&quot;&gt;Data Layer&lt;/a&gt;. If multiple
third parties wish to trigger conversion-tracking data, they can do this by
pulling from the Data Layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Risks when using Tag managers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When using a tag manager, great care needs to be taken to avoid slowing down how
quickly pages load. This is because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Anyone with credentials and access can easily add not just more tags, but
&lt;em&gt;any&lt;/em&gt; JavaScript they want. Although tag managers can load tags
asynchronously, this can still lead to an excess of costly HTTP requests being
made and executed. This can be minimized by only allowing one user to publish
versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Anyone can configure too many tag manager &lt;a href=&quot;https://support.google.com/analytics/answer/6164470&quot; rel=&quot;noopener&quot;&gt;auto-event listeners&lt;/a&gt;. Every
auto-event listener needs to be executed &amp;amp; the more code and network requests
there are, the longer it can take for a page to fully load. With our
performance guidance encouraging that you &lt;a href=&quot;https://web.dev/rail/&quot;&gt;respond to events within 50ms&lt;/a&gt;, every tag manager event listener
added eats away at that goal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;avoid-scripts-that-pollute-the-global-scope&quot;&gt;Avoid scripts that pollute the global scope &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#avoid-scripts-that-pollute-the-global-scope&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Third-party scripts injected into the unknown can sometimes load a number of
their own JavaScript dependencies. This can pollute the global scope and cause
accidental breakage in pages.&lt;/p&gt;
&lt;p&gt;There is also no guarantee that code loaded from a third-party will remain the
same as what you saw during testing. New features can be pushed out by third
parties at any time, potentially breaking your page. Self-testing, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Security/Subresource_Integrity&quot; rel=&quot;noopener&quot;&gt;sub-resource integrity&lt;/a&gt;
and securely transmitting third-party code (to reduce the risk of in-transit
modifications) can help here.&lt;/p&gt;
&lt;p&gt;Be sure to conduct careful audits of the third-party scripts you load to ensure
they’re being good actors.&lt;/p&gt;
&lt;h2 id=&quot;mitigation-strategies&quot;&gt;Mitigation strategies &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#mitigation-strategies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adding third-party scripts to a page implies a level of trust in the origin.
There are some strategies you can take to minimize their impact on performance
and security:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/why-https-matters/&quot;&gt;HTTPS&lt;/a&gt;&lt;/strong&gt; is a
must. Sites working over HTTPS shouldn’t have third-parties working over HTTP.
An HTTPS page that includes content fetched using HTTP is called a mixed
content page and will run into &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Security/Mixed_content&quot; rel=&quot;noopener&quot;&gt;Mixed Content&lt;/a&gt;
warnings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider the &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/HTML/Element/iframe&quot; rel=&quot;noopener&quot;&gt;sandbox attribute&lt;/a&gt;&lt;/strong&gt; on
iframes. From a security perspective, this allows you to restrict the actions
available from the iframe. Restrictions include &lt;code&gt;allow-scripts&lt;/code&gt;controlling
whether the context can run scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/CSP&quot; rel=&quot;noopener&quot;&gt;Content Security Policy&lt;/a&gt;&lt;/strong&gt; (CSP).
Through a HTTP header in your server’s response, you can define behaviors that
are trusted in the page. CSP can be used to detect and mitigate against the
effects of certain attacks, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_scripting&quot; rel=&quot;noopener&quot;&gt;Cross Site Scripting&lt;/a&gt; (XSS).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CSP is particularly powerful as it includes directives such as
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src&quot; rel=&quot;noopener&quot;&gt;script-src&lt;/a&gt;
that specifies what are valid, allowed sources for JavaScript. Below is an
example of how this can be used in practice:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;// Given this CSP header Content-Security-Policy: script-src&lt;br /&gt;https://example.com/ // The following third-party script will not be loaded or&lt;br /&gt;executed&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://not-example.com/js/library.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With sites relying on more third-party scripts than ever, it’s paramount not to
ignore third-party script performance. Good things you can do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Become familiar with some of the most effective third-party script
optimization methods like only loading tags that support the async loading
pattern.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Understand how to identify and fix issues with third-party script loading.
This can help you take back control of your page load performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party script optimization should be followed by on-going real-time
performance monitoring of your scripts and communication with your third-party
providers. The web is evolving at a rapid pace and a script’s locally observed
performance gives no guarantees that it will perform as well in the future or in
the wild.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://csswizardry.com/2017/07/performance-and-resilience-stress-testing-third-parties/&quot; rel=&quot;noopener&quot;&gt;Performance and Resilience: Stress-Testing Third Parties&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/&quot;&gt;Adding interactivity with JavaScript&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://css-tricks.com/potential-dangers-of-third-party-javascript/&quot; rel=&quot;noopener&quot;&gt;Potential dangers with Third-party Scripts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.twnsnd.com/posts/performant_third_party_scripts.html&quot; rel=&quot;noopener&quot;&gt;How 3rd Party Scripts can be performant citizens on the web&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://speakerdeck.com/csswizardry/why-fast-matters&quot; rel=&quot;noopener&quot;&gt;Why Fast Matters - CSS Wizardry&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.troyhunt.com/the-javascript-supply-chain-paradox-sri-csp-and-trust-in-third-party-libraries/&quot; rel=&quot;noopener&quot;&gt;The JavaScript Supply Chain Paradox: SRI, CSP and Trust in Third Party Libraries&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jakearchibald.com/2018/third-party-css-is-not-safe/&quot; rel=&quot;noopener&quot;&gt;Third-party CSS isn&#39;t safe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Kenji Baheux, Jeremy Wagner, Pat Meenan, Philip Walton, Jeff
Posnick and Cheney Tsai for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Arthur Evans</name>
    </author>
  </entry>
  
  <entry>
    <title>Webpack</title>
    <link href="https://web.dev/webpack/"/>
    <updated>2018-02-08T00:00:00Z</updated>
    <id>https://web.dev/webpack/</id>
    <content type="html" mode="escaped">&lt;p&gt;Modern web applications often use a &lt;strong&gt;bundling tool&lt;/strong&gt; to create a production
&amp;quot;bundle&amp;quot; of files (scripts, stylesheets, etc.) that is
&lt;a href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/&quot;&gt;optimized&lt;/a&gt;,
&lt;a href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/&quot;&gt;minified&lt;/a&gt;
and can be downloaded in less time by your users. In &lt;strong&gt;Web Performance
Optimization with webpack&lt;/strong&gt;, we will walk through how to effectively optimize
site resources using &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;. This can help users
load and interact with your sites more quickly.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Webpack logo.&quot; decoding=&quot;async&quot; height=&quot;311&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/14nTVvq5PEzMdpksfenJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;webpack is one of the most popular bundling tools in use today. Taking advantage
of its features for optimizing modern code,
&lt;a href=&quot;https://web.dev/use-long-term-caching/#lazy-load-code-that-you-dont-need-right-now&quot;&gt;code-splitting&lt;/a&gt;
scripts into critical and non-critical pieces and stripping out unused code (to
name but a few optimizations) can ensure your app has a minimal network and
processing cost.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Before and after applying JavaScript   optimizations. Time-to-Interactive is improved&quot; decoding=&quot;async&quot; height=&quot;575&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9IVFhBrXUo9CU1Hwl0FK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;p&gt;Inspired by &lt;a href=&quot;http://www.susielu.com/data-viz/bundle-buddy&quot;&gt;
    Code-splitting in Bundle Buddy&lt;/a&gt; by Susie Lu&lt;/p&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; We created a training app to play with optimizations described in this article. Try squeezing the most out of it to practice the tips: &lt;a href=&quot;https://github.com/GoogleChromeLabs/webpack-training-project&quot;&gt;&lt;code&gt;webpack-training-project&lt;/code&gt;&lt;/a&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Let’s get started by looking at optimizing one of the costliest resources in a
modern app – JavaScript.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/decrease-frontend-size&quot;&gt;Decrease Front-end
Size&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/use-long-term-caching&quot;&gt;Make Use of Long-term
Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/monitor-and-analyze&quot;&gt;Monitor and analyze the
app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/webpack-conclusion/&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>JavaScript Start-up Optimization</title>
    <link href="https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/"/>
    <updated>2017-11-30T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/</id>
    <content type="html" mode="escaped">&lt;p&gt;As we build sites more heavily reliant on JavaScript, we sometimes pay for what
we send down in ways that we can’t always easily see. In this article, we’ll
cover why a little &lt;strong&gt;discipline&lt;/strong&gt; can help if you’d like your site to load and be
interactive quickly on mobile devices. Delivering less JavaScript can mean less
time in network transmission, less spent decompressing code and less time
parsing and compiling this JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;network&quot;&gt;Network &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#network&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When most developers think about the cost of JavaScript, they think about it in
terms of the &lt;strong&gt;download and execution cost&lt;/strong&gt;. Sending more bytes of JavaScript
over the wire takes longer the slower a user’s connection is.&lt;/p&gt;
&lt;img alt=&quot;When a browser requests a resource, that resource needs to be fetched and then decompressed. In the case of resources like JavaScript, they must be parsed and compiled prior to execution.&quot; decoding=&quot;async&quot; height=&quot;493&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Yt8aD7AoCbAT20mYqaUm.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This can be a problem as the &lt;strong&gt;effective network
connection type&lt;/strong&gt; a user has might not actually be 3G, 4G or Wi-Fi. You can be on
coffee-shop Wi-Fi but connected to a cellular hotspot with 2G speeds.&lt;/p&gt;
&lt;p&gt;You can &lt;strong&gt;reduce&lt;/strong&gt; the network transfer cost of JavaScript through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Only sending the code a user needs&lt;/strong&gt;.
&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&quot;https://web.dev/web/updates/2017/06/supercharged-codesplit&quot;&gt;code-splitting&lt;/a&gt; to break
up your JavaScript into what is critical and what is not. Module bundlers
like &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; support
&lt;a href=&quot;https://webpack.js.org/guides/code-splitting/&quot; rel=&quot;noopener&quot;&gt;code-splitting&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lazily loading in code that is non-critical.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minification&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&quot;https://github.com/mishoo/UglifyJS&quot; rel=&quot;noopener&quot;&gt;UglifyJS&lt;/a&gt; for
&lt;a href=&quot;https://web.dev/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#minification_preprocessing_context-specific_optimizations&quot;&gt;minifying&lt;/a&gt;
ES5 code.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;https://github.com/babel/minify&quot; rel=&quot;noopener&quot;&gt;babel-minify&lt;/a&gt; or
&lt;a href=&quot;https://www.npmjs.com/package/uglify-es&quot; rel=&quot;noopener&quot;&gt;uglify-es&lt;/a&gt; to minify ES2015+.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;At minimum, use
&lt;a href=&quot;https://web.dev/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#text_compression_with_gzip&quot;&gt;gzip&lt;/a&gt;
to compress text-based resources.&lt;/li&gt;
&lt;li&gt;Consider using
&lt;a href=&quot;https://www.smashingmagazine.com/2016/10/next-generation-server-compression-with-brotli/&quot; rel=&quot;noopener&quot;&gt;Brotli&lt;/a&gt;
~&lt;a href=&quot;https://twitter.com/paulcalvano/status/924660429846208514&quot; rel=&quot;noopener&quot;&gt;q11&lt;/a&gt;. Brotli
outperforms gzip on compression ratio. It helped CertSimple save
&lt;a href=&quot;https://speakerdeck.com/addyosmani/the-browser-hackers-guide-to-instant-loading?slide=30&quot; rel=&quot;noopener&quot;&gt;17%&lt;/a&gt;
on the size of compressed JS bytes and LinkedIn save
&lt;a href=&quot;https://engineering.linkedin.com/blog/2017/05/boosting-site-speed-using-brotli-compression&quot; rel=&quot;noopener&quot;&gt;4%&lt;/a&gt;
on their load times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Removing unused code&lt;/strong&gt;.
&lt;ul&gt;
&lt;li&gt;Identify opportunities for code that can be removed or lazily loaded in
with &lt;a href=&quot;https://web.dev/web/updates/2017/04/devtools-release-notes#coverage&quot;&gt;DevTools code
coverage&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use
&lt;a href=&quot;https://github.com/babel/babel/tree/main/packages/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;babel-preset-env&lt;/a&gt;
and browserlist to avoid transpiling features already in modern browsers.
Advanced developers may find careful &lt;a href=&quot;https://github.com/webpack-contrib/webpack-bundle-analyzer&quot; rel=&quot;noopener&quot;&gt;analysis of their webpack
bundles&lt;/a&gt; helps
identify opportunities to trim unneeded dependencies.&lt;/li&gt;
&lt;li&gt;For stripping code, see
&lt;a href=&quot;https://webpack.js.org/guides/tree-shaking/&quot; rel=&quot;noopener&quot;&gt;tree-shaking&lt;/a&gt;, &lt;a href=&quot;https://web.dev/closure/compiler/&quot;&gt;Closure
Compiler&lt;/a&gt;’s advanced optimizations and library
trimming plugins like
&lt;a href=&quot;https://github.com/lodash/babel-plugin-lodash&quot; rel=&quot;noopener&quot;&gt;lodash-babel-plugin&lt;/a&gt; or
webpack’s
&lt;a href=&quot;https://iamakulov.com/notes/webpack-front-end-size-caching/#moment-js&quot; rel=&quot;noopener&quot;&gt;ContextReplacementPlugin&lt;/a&gt;
for libraries like Moment.js.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching code to minimize network trips.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&quot;https://web.dev/web/fundamentals/performance/optimizing-content-efficiency/http-caching&quot;&gt;HTTP
caching&lt;/a&gt;
to ensure browsers cache responses effectively. Determine optimal
lifetimes for scripts (max-age) and supply validation tokens (ETag) to avoid
transferring unchanged bytes.&lt;/li&gt;
&lt;li&gt;Service Worker caching can make your app network resilient and give you
eager access to features like &lt;a href=&quot;https://v8project.blogspot.com/2015/07/code-caching.html&quot; rel=&quot;noopener&quot;&gt;V8’s code
cache&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use long-term caching to avoid having to re-fetch resources that haven&#39;t
changed. If using Webpack, see &lt;a href=&quot;https://webpack.js.org/guides/caching/&quot; rel=&quot;noopener&quot;&gt;filename
hashing&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;parsecompile&quot;&gt;Parse/Compile &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#parsecompile&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once downloaded, one of JavaScript’s &lt;strong&gt;heaviest&lt;/strong&gt; costs is the time for a JS
engine to &lt;strong&gt;parse/compile&lt;/strong&gt; this code. In &lt;a href=&quot;https://web.dev/web/tools/chrome-devtools/&quot;&gt;Chrome
DevTools&lt;/a&gt;, parse and compile are part of the yellow
&amp;quot;Scripting&amp;quot; time in the Performance panel.&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;165&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xSTnKzQ7pXR9znVfDBL3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The Bottom-Up and Call Tree tabs show you exact Parse/compile timings:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;228&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/idCp6NvAEITLFHkQgJUq.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
 &lt;figcaption&gt; Chrome
DevTools Performance panel &gt; Bottom-Up. With V8’s Runtime Call Stats enabled, we
can see time spent in phases like Parse and Compile &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; Performance panel support for Runtime Call Stats is currently experimental. To enable, go to about://flags/#enable-devtools-experiments -&amp;gt; restart Chrome -&amp;gt; go to DevTools -&amp;gt; Settings -&amp;gt; Experiments -&amp;gt; hit shift 6 times -&amp;gt; check the option called &lt;code&gt;Timeline: V8 Runtime Call Stats on Timeline&lt;/code&gt; and close then re-open DevTools. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;But, why does this matter?&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;221&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/7b4TzW13lTWH2OwUEXKQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Spending a long time parsing/compiling code can heavily delay how soon a user
can interact with your site. The more JavaScript you send, the longer it will
take to parse and compile it before your site is interactive.&lt;/p&gt;
&lt;p&gt;Byte-for-byte, &lt;strong&gt;JavaScript is more expensive for the browser to process than
the equivalently sized image or Web Font&lt;/strong&gt; — Tom Dale&lt;/p&gt;
&lt;p&gt;Compared to JavaScript, there are numerous costs involved in processing
equivalently sized images (they still have to be decoded!) but on average mobile
hardware, JS is more likely to negatively impact a page’s interactivity.&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;517&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/EjFNNhzfs6NOgLItAaSD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
 &lt;figcaption&gt;JavaScript
and image bytes have very different costs. Images usually don’t block the main
thread or prevent interfaces from getting interactive while being decoded and
rasterized. JS however can delay interactivity due to parse, compile and
execution costs.&lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;When we talk about parse and compile being slow; context is important — we’re
talking about &lt;strong&gt;average&lt;/strong&gt; mobile phones here. &lt;strong&gt;Average users can have phones
with slow CPUs and GPUs, no L2/L3 cache and which may even be memory
constrained.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Network capabilities and device capabilities don’t always match up. A user
with an amazing Fiber connection doesn’t necessarily have the best CPU to
parse and evaluate JavaScript sent to their device. This is also true in
reverse… a terrible network connection, but a blazing fast CPU. — Kristofer
Baxter, LinkedIn&lt;/p&gt;
&lt;p&gt;Below we can see the cost of parsing ~1MB of decompressed (simple) JavaScript on
low and high-end hardware. &lt;strong&gt;There is a 2–5x difference in time to parse/compile
code between the fastest phones on the market and average phones&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&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/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/rNpXFldjEUV3pRQUdLf6.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt; &lt;figcaption&gt;This graph
highlights parse times for a 1MB bundle of JavaScript (~250KB gzipped) across
desktop and mobile devices of differing classes. When looking at the cost of
parse, it’s the decompressed figures to consider e.g ~250KB gzipped JS
decompresses to ~1MB of code.&lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;What about a real-world site, like CNN.com?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the high-end iPhone 8 it takes just ~4s to parse/compile CNN’s JS compared
to ~13s for an average phone (Moto G4)&lt;/strong&gt;. This can significantly impact how
quickly a user can fully interact with this site.&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&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/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/9352CA33sU4ISpPpJQvu.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;Above we
see parse times comparing the performance of Apple’s A11 Bionic chip to the
Snapdragon 617 in more average Android hardware.&lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;This highlights the importance of testing on &lt;strong&gt;average&lt;/strong&gt; hardware (like the Moto
G4) instead of just the phone that might be in your pocket. Context matters
however: &lt;strong&gt;optimize for the device and network conditions your users have.&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&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/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/el8cWy14rn3GnZ3WSJof.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
 &lt;figcaption&gt;Google
Analytics can provide insight into the &lt;a href=&quot;https://crossbrowsertesting.com/blog/development/use-google-analytics-find-devices-customers-use/&quot;&gt;mobile
device classes&lt;/a&gt; your real users are accessing your site with. This can
provide opportunities to understand the real CPU/GPU constraints they’re
operating with.&lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Are we really sending down too much JavaScript? Err, possibly :)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using HTTP Archive (top ~500K sites) to analyze the state of &lt;a href=&quot;http://beta.httparchive.org/reports/state-of-javascript#bytesJs&quot; rel=&quot;noopener&quot;&gt;JavaScript on
mobile&lt;/a&gt;, we can
see that 50% of sites take over 14 seconds to get interactive. These sites spend
up to 4 seconds just parsing and compiling JS.&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;445&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PppRmvEBsCkQ44xyC0Pu.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Factor in the time it takes to fetch and process JS and other resources and it’s
perhaps not surprising that users can be left waiting a while before feeling
pages are ready to use. We can definitely do better here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Removing non-critical JavaScript from your pages can reduce transmission
times, CPU-intensive parsing and compiling and potential memory overhead. This
also helps get your pages interactive quicker.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;execution-time&quot;&gt;Execution time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#execution-time&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s not just parse and compile that can have a cost. &lt;strong&gt;JavaScript execution&lt;/strong&gt;
(running code once parsed/compiled) is one of the operations that has to happen
on the main thread. Long execution times can also push out how soon a user can
interact with your site.&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&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/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/neG3PZcNmc3rqRXyZnQS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;If script executes for more than 50ms, time-to-interactive is delayed by the
&lt;em&gt;entire&lt;/em&gt; amount of time it takes to download, compile, and execute the JS —
Alex Russell&lt;/p&gt;
&lt;p&gt;To address this, JavaScript benefits from being in &lt;strong&gt;small chunks&lt;/strong&gt; to avoid
locking up the main thread. Explore if you can reduce how much work is being
done during execution.&lt;/p&gt;
&lt;h2 id=&quot;other-costs&quot;&gt;Other costs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#other-costs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JavaScript can impact page performance in other ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory. Pages can appear to jank or pause frequently due to GC (garbage
collection). When a browser reclaims memory, JS execution is paused so a
browser frequently collecting garbage can pause execution more frequently than
we may like. Avoid &lt;a href=&quot;https://developer.chrome.com/docs/devtools/memory-problems/&quot; rel=&quot;noopener&quot;&gt;memory leaks&lt;/a&gt;
and frequent gc pauses to keep pages jank free.&lt;/li&gt;
&lt;li&gt;During runtime, long-running JavaScript can block the main-thread causing
pages that are unresponsive. Chunking up work into smaller pieces (using
&lt;code&gt;&lt;a href=&quot;https://web.dev/web/fundamentals/performance/rendering/optimize-javascript-execution#use_requestanimationframe_for_visual_changes&quot;&gt;requestAnimationFrame()&lt;/a&gt;&lt;/code&gt;
or &lt;code&gt;&lt;a href=&quot;https://web.dev/web/updates/2015/08/using-requestidlecallback&quot;&gt;requestIdleCallback()&lt;/a&gt;&lt;/code&gt;
for scheduling) can minimize responsiveness issues which can help improve &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;patterns-for-reducing-javascript-delivery-cost&quot;&gt;Patterns for reducing JavaScript delivery cost &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#patterns-for-reducing-javascript-delivery-cost&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you’re trying to keep parse/compile and network transmit times for JavaScript
slow, there are patterns that can help like route-based chunking or
&lt;a href=&quot;https://web.dev/web/fundamentals/performance/prpl-pattern/&quot;&gt;PRPL&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;prpl&quot;&gt;PRPL &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#prpl&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PRPL (Push, Render, Pre-cache, Lazy-load) is a pattern that optimizes for
interactivity through aggressive code-splitting and caching:&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;436&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JEMofg8IloPHYfMQbiFd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Let’s visualize the impact it can have.&lt;/p&gt;
&lt;p&gt;We analyze the load-time of popular mobile sites and Progressive Web Apps using
V8’s Runtime Call Stats. As we can see, parse time (shown in orange) is a
significant portion of where many of these sites spend their time:&lt;/p&gt;
&lt;img alt=&quot;ALT_TEXT_HERE&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/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RxxGASjEChijlqo3ODBC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;a href=&quot;https://www.wego.com/&quot; rel=&quot;noopener&quot;&gt;Wego&lt;/a&gt;, a site that uses PRPL, manages to maintain a low parse
time for their routes, getting interactive very quickly. Many of the other sites
above adopted code-splitting and performance budgets to try lowering their JS
costs.&lt;/p&gt;
&lt;h3 id=&quot;progressive-bootstrapping&quot;&gt;Progressive Bootstrapping &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#progressive-bootstrapping&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many sites optimize content visibility at the expensive of interactivity. To get
a fast first paint when you do have large JavaScript bundles, developers
sometimes employ server-side rendering; then &amp;quot;upgrade&amp;quot; it to attach event
handlers when the JavaScript finally gets fetched.&lt;/p&gt;
&lt;p&gt;Be careful — this has its own costs. You 1) generally send down a &lt;em&gt;larger&lt;/em&gt; HTML
response which can push our interactivity, 2) can leave the user in an uncanny
valley where half the experience can’t actually be interactive until JavaScript
finishes processing.&lt;/p&gt;
&lt;p&gt;Progressive Bootstrapping may be a better approach. Send down a minimally
functional page (composed of just the HTML/JS/CSS needed for the current route).
As more resources arrive, the app can lazy-load and unlock more features.&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;303&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/BcP0V4ROh8hwlzSD6PuA.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
 &lt;figcaption&gt; &lt;a href=&quot;https://twitter.com/aerotwist/status/729712502943174657&quot;&gt;Progressive
Bootstrapping&lt;/a&gt; by Paul Lewis &lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;Loading code proportionate to what’s in view is the holy grail. PRPL and
Progressive Bootstrapping are patterns that can help accomplish this.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Transmission size is critical for low end networks. Parse time is important
for CPU bound devices. Keeping these low matters.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Teams have found success adopting strict performance budgets for keeping their
JavaScript transmission and parse/compile times low. See Alex Russell’s &amp;quot;&lt;a href=&quot;https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/&quot; rel=&quot;noopener&quot;&gt;Can You
Afford It?: Real-world Web Performance
Budgets&lt;/a&gt;&amp;quot;
for guidance on budgets for mobile.&lt;/p&gt;
&lt;figure&gt; &lt;img alt=&quot;ALT_TEXT_HERE&quot; decoding=&quot;async&quot; height=&quot;471&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Fey2HrvHZVHbvZKuykVW.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
 &lt;figcaption&gt;It’s
useful to consider how much JS &quot;headroom&quot; the architectural decisions we make
can leave us for app logic.&lt;/figcaption&gt; &lt;/figure&gt;
&lt;p&gt;If you’re building a site that targets mobile devices, do your best to develop
on representative hardware, keep your JavaScript parse/compile times low and
adopt a Performance Budget for ensuring your team are able to keep an eye on
their JavaScript costs.&lt;/p&gt;
&lt;h2 id=&quot;learn-more&quot;&gt;Learn More &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-javascript-startup-optimization/#learn-more&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=_srJ7eHS3IM&quot; rel=&quot;noopener&quot;&gt;Chrome Dev Summit 2017 - Modern Loading Best
Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/reloading/javascript-start-up-performance-69200f43b201&quot; rel=&quot;noopener&quot;&gt;JavaScript Start-up
Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nolanlawson.github.io/frontendday-2016/&quot; rel=&quot;noopener&quot;&gt;Solving the web performance
crisis&lt;/a&gt; — Nolan Lawson&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/&quot; rel=&quot;noopener&quot;&gt;Can you afford it? Real-world performance
budgets&lt;/a&gt;
— Alex Russell&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/kristoferbaxter/status/908144931125858304&quot; rel=&quot;noopener&quot;&gt;Evaluating web frameworks and
libraries&lt;/a&gt; —
Kristofer Baxter&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/results-experimenting-brotli/&quot; rel=&quot;noopener&quot;&gt;Cloudflare’s Results of experimenting with
Brotli&lt;/a&gt; for
compression (note dynamic Brotli at a higher quality can delay initial page
render so evaluate carefully. You probably want to statically compress
instead.)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@samccone/performance-futures-bundling-281543d9a0d5&quot; rel=&quot;noopener&quot;&gt;Performance
Futures&lt;/a&gt;
— Sam Saccone&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Data-binding revolutions with Object.observe()</title>
    <link href="https://web.dev/es7-observe/"/>
    <updated>2014-05-20T00:00:00Z</updated>
    <id>https://web.dev/es7-observe/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-warn-bg color-state-warn-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block color-state-warn-text&quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Warning sign&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M23 21L12 2 1 21h22zm-12-3v-2h2v2h-2zm0-4h2v-4h-2v4z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; In November 2015, it was &lt;a href=&quot;https://esdiscuss.org/topic/an-update-on-object-observe&quot;&gt;announced on esdiscuss&lt;/a&gt; that the &lt;code&gt;Object.observe()&lt;/code&gt; proposal is being withdrawn from TC39. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A revolution is coming. There’s a new addition to JavaScript that’s going to change &lt;strong&gt;everything&lt;/strong&gt; you think you know about data-binding. It’s also going to change how many of your MVC libraries approach observing models for edits and updates. Are you ready for some sweet performance boosts to apps that care about property observation?&lt;/p&gt;
&lt;p&gt;Okay. Okay. Without further delay, I’m happy to announce &lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:observe&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Object.observe()&lt;/code&gt;&lt;/a&gt; has landed in &lt;a href=&quot;http://www.chromestatus.com/features/6147094632988672&quot; rel=&quot;noopener&quot;&gt;Chrome 36&lt;/a&gt; stable. &lt;strong&gt;[WOOOO. THE CROWD GOES WILD]&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Object.observe()&lt;/code&gt;, part of a future ECMAScript standard, is a method for asynchronously observing changes to JavaScript objects… without the need for a separate library. It allows an observer to receive a time-ordered sequence of change records which describe the set of changes which took place to a set of observed objects.&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;// Let&#39;s say we have a model with data&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Which we then observe&lt;/span&gt;&lt;br /&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// This asynchronous callback runs&lt;/span&gt;&lt;br /&gt;    changes&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 keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;change&lt;/span&gt;&lt;span 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;// Letting us know what changed&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;change&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; change&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; change&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oldValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&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;Anytime a change is made, it gets reported:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Change reported.&quot; decoding=&quot;async&quot; height=&quot;257&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 686px) 686px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/AyTEBW6MUiau9OXMaVOG.png?auto=format&amp;w=1372 1372w&quot; width=&quot;686&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With &lt;code&gt;Object.observe()&lt;/code&gt; (I like to call it O.o() or Oooooooo), you can implement two-way data-binding &lt;a href=&quot;http://bitworking.org/news/2014/05/zero_framework_manifesto&quot; rel=&quot;noopener&quot;&gt;without the need for a framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s not to say you shouldn’t use one. For large projects with complicated business logic, opinionated frameworks are invaluable and you should continue to use them. They simplify the orientation of new developers, require less code maintenance and impose patterns on how to achieve common tasks. When you don’t need one, you can use smaller, more focused libraries like &lt;a href=&quot;http://polymer-project.org/&quot; rel=&quot;noopener&quot;&gt;Polymer&lt;/a&gt; (which already take advantage of O.o()).&lt;/p&gt;
&lt;p&gt;Even if you find yourself heavily using a framework or MV* library, O.o() has the potential to provide them with some healthy performance improvements, with a faster, simpler implementation whilst keeping the same API. For example, &lt;a href=&quot;https://mail.mozilla.org/pipermail/es-discuss/2012-September/024978.html&quot; rel=&quot;noopener&quot;&gt;last year Angular found&lt;/a&gt; that in a benchmark where changes were being made to a model, dirty-checking took 40ms per update and O.o() took 1-2ms per update (an improvement of 20-40x faster).&lt;/p&gt;
&lt;p&gt;Data-binding without the need for tons of complicated code also means you no longer have to poll for changes, so longer battery life!&lt;/p&gt;
&lt;p&gt;If you&#39;re already sold on O.o(), skip-ahead to the feature introduction, or read ahead for more on the problems it solves.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-want-to-observe&quot;&gt;What do we want to observe? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#what-do-we-want-to-observe&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When we’re talking about data observation, we’re usually referring to keeping an eye out for some specific types of changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changes to raw JavaScript objects&lt;/li&gt;
&lt;li&gt;When properties get added, changed, deleted&lt;/li&gt;
&lt;li&gt;When arrays have elements spliced in and out of them&lt;/li&gt;
&lt;li&gt;Changes to the prototype of the object&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-importance-of-data-binding&quot;&gt;The importance of data-binding &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#the-importance-of-data-binding&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data-binding starts to become important when you care about model-view control separation. HTML is a great declarative mechanism, but it’s completely static. Ideally, you just want to declare the relationship between your data and the DOM and keep the DOM up to date. This creates leverage and saves you a lot of time writing really repetitive code that just sends data to and from the DOM between your application’s internal state or the server.&lt;/p&gt;
&lt;p&gt;Data-binding is particularly useful when you have a complex user-interface where you need to wire up relationships between multiple properties in your data models with multiple elements in your views. This is pretty common in the single-page applications we’re building today.&lt;/p&gt;
&lt;p&gt;By baking a way to natively observe data in the browser, we give JavaScript frameworks (and small utility libraries you write) a way to observe changes to model data without relying on some of the slow hacks the world uses today.&lt;/p&gt;
&lt;h2 id=&quot;what-the-world-looks-like-today&quot;&gt;What the world looks like today &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#what-the-world-looks-like-today&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Dirty-checking&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Where have you seen data-binding before? Well, if you use a modern MV* library for building your webapps (e.g Angular, Knockout) you’re probably used to binding model data to the DOM. As a refresher, here’s an example of a Phone list app where we’re binding the value of each phone in a &lt;code&gt;phones&lt;/code&gt; array (defined in JavaScript) to a list item so that our data and UI are always in sync:&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;html ng&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;angular.js&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;controller.js&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;head&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;body ng&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;controller&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;PhoneListCtrl&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;li ng&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;repeat&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;phone in phones&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;li&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&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;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;body&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;html&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 JavaScript for the controller:&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;var&lt;/span&gt; phonecatApp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; angular&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;phonecatApp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;phonecatApp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;PhoneListCtrl&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  $scope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;phones &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Nexus S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token string-property property&quot;&gt;&#39;snippet&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Fast just got faster with Nexus S.&#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 string-property property&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Motorola XOOM with Wi-Fi&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token string-property property&quot;&gt;&#39;snippet&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;The Next, Next Generation tablet.&#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 string-property property&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MOTOROLA XOOM&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token string-property property&quot;&gt;&#39;snippet&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;The Next, Next Generation tablet.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Anytime the underlying model data changes, our list in the DOM gets updated. How does Angular achieve this? Well, behind the scenes it’s doing something called dirty-checking.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Dirty checking&quot; decoding=&quot;async&quot; height=&quot;446&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8NhwcWyZJiLZS5k4EEru.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The basic idea with dirty-checking is that anytime data could have changed, the library has to go and check if it did change via a digest or change cycle. In Angular’s case, a digest cycle identifies all expressions registered to be watched to see if there’s a change. It &lt;a href=&quot;http://stackoverflow.com/questions/9682092/databinding-in-angularjs/9693933#9693933&quot; rel=&quot;noopener&quot;&gt;knows&lt;/a&gt; about a model’s previous values and if they have changed, a change event is fired. For a developer, the main benefit here is that you get to use raw JavaScript object data which is pleasant to use and composes fairly well. The downside is that it has bad algorithmic behavior and is potentially very expensive.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Dirty checking.&quot; decoding=&quot;async&quot; height=&quot;431&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RjWKA54O8RSUxYjEZ13M.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The expense of this operation is proportional to the total number of observed objects. I may need to do a lot of dirty checking. Also may need a way to trigger dirty-checking when data &lt;em&gt;might&lt;/em&gt; have changed. There are lots of clever tricks frameworks use for this. It&#39;s unclear if this is ever going to be perfect.&lt;/p&gt;
&lt;p&gt;The web ecosystem should have more ability to innovate and evolve its own declarative mechanisms, e.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Constraint-based model systems&lt;/li&gt;
&lt;li&gt;Auto-persistence systems (e.g persisting changes to IndexedDB or localStorage)&lt;/li&gt;
&lt;li&gt;Container objects (Ember, Backbone)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://www.slideshare.net/mixonic/containers-di&quot; rel=&quot;noopener&quot;&gt;Container&lt;/a&gt; objects are where a framework creates objects which on the inside hold the data. They have accessors to the data and they can capture what you set or get and internally broadcast. This works well. It&#39;s relatively performant and has good algorithmic behavior. An example of container objects using Ember can be found below:&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;// Container objects&lt;/span&gt;&lt;br /&gt;MyApp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;president &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Ember&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;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;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Barack Obama&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;MyApp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;country &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Ember&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;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 comment&quot;&gt;// ending a property with &quot;Binding&quot; tells Ember to&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// create a binding to the presidentName property&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;presidentNameBinding&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MyApp.president.name&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Later, after Ember has resolved bindings&lt;/span&gt;&lt;br /&gt;MyApp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;country&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;presidentName&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// &quot;Barack Obama&quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Data from the server needs to be converted&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Composes poorly with existing code&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The expense of discovering what changed here is proportional to the number of things that changed. Another problem is now you&#39;re using this different kind of object. Generally speaking you have to convert from data you&#39;re getting from the server to these objects so they&#39;re observable.&lt;/p&gt;
&lt;p&gt;This doesn&#39;t compose particularly well with existing JS code because most code assumes it can operate on raw data. Not for these these specialized kinds of objects.&lt;/p&gt;
&lt;h2 id=&quot;introducing-objectobserve&quot;&gt;&lt;code&gt;Introducing Object.observe()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#introducing-objectobserve&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ideally what we want is the best of both worlds - a way to observe data with support for raw data objects (regular JavaScript objects) if we choose to AND without the need to dirty-check everything all the time. Something with good algorithmic behavior. Something that composes well and is baked into the platform. This is the beauty of what &lt;code&gt;Object.observe()&lt;/code&gt; brings to the table.&lt;/p&gt;
&lt;p&gt;It allows us to observe an object, mutate properties and see the change report of what has changed. But enough about the theory, let’s look at some code!&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Object.observe()&quot; decoding=&quot;async&quot; height=&quot;448&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/mZEHsJKa7hgENbT7btX3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;objectobserve-and-objectunobserve&quot;&gt;Object.observe() and Object.unobserve() &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#objectobserve-and-objectunobserve&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s imagine that we have a simple vanilla JavaScript object representing a model:&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;// A model can be a simple vanilla object&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; todoModel &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;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Default&#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;completed&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We can then specify a callback for whenever mutations (changes) are made to the object:&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;observer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  changes&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 keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;change&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;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;&lt;span class=&quot;token string&quot;&gt;&#39;what property changed? &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; change&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;&lt;span class=&quot;token string&quot;&gt;&#39;how did it change? &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; change&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;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;&lt;span class=&quot;token string&quot;&gt;&#39;whats the current value? &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; change&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;change&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;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;change&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// all changes&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;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; When the observer callback is invoked, the observed objects may have been changed multiple times, so for each change, the new value (the value following each change) and the current value (the final value) aren&#39;t necessarily the same thing. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;We can then observe these changes using O.o(), passing in the object as our first argument and the callback as our second:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&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;Let’s start making some changes to our Todos model object:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Buy some more milk&#39;&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;Looking at the console, we get back some useful information! We know what property changed, how it was changed and what the new value is.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Console report&quot; decoding=&quot;async&quot; height=&quot;259&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 685px) 685px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/SuipCSKRhKasAwoLxssX.png?auto=format&amp;w=1370 1370w&quot; width=&quot;685&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Woo! Goodbye, dirty-checking! Your tombstone should be carved in Comic Sans. Let’s change another property. This time &lt;code&gt;completeBy&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;completeBy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;01/01/2014&#39;&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;As we can see we once again successfully get back a change report:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Change report.&quot; decoding=&quot;async&quot; height=&quot;253&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 689px) 689px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/HYrWbPQDDPyZo9mxdZA1.png?auto=format&amp;w=1378 1378w&quot; width=&quot;689&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Great. What if we now decided to delete the ‘completed’ property from our object:&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;delete&lt;/span&gt; todoModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;completed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Completed&quot; decoding=&quot;async&quot; height=&quot;261&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 686px) 686px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Rw7ym71bRXj07vQWgPEx.png?auto=format&amp;w=1372 1372w&quot; width=&quot;686&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;As we can see, the report of changes returned includes information about the deletion. As expected, the new value of the property is now undefined. So, we now know you can find out when properties have been added. When they&#39;ve been deleted. Basically, the &lt;strong&gt;set&lt;/strong&gt; of properties on an object (&amp;quot;new&amp;quot;, &amp;quot;deleted&amp;quot;, &amp;quot;reconfigured&amp;quot;) and it&#39;s prototype changing (&lt;em&gt;proto&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;As in any observation system, a method also exists to stop listening out for changes. In this case, it’s &lt;code&gt;Object.unobserve()&lt;/code&gt;, which has the same signature as O.o() but can be called as follows:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unobserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&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;As we can see below, any mutations made to the object after this has been run no longer result in a list of change records being returned.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Mutations&quot; decoding=&quot;async&quot; height=&quot;259&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 684px) 684px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/oznJVQJ0gVHuAlsHhY86.png?auto=format&amp;w=1368 1368w&quot; width=&quot;684&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;specifying-changes-of-interest&quot;&gt;Specifying changes of interest &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#specifying-changes-of-interest&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So we’ve looked at the basics behind how to get back a list of changes to an observed object. What if you’re interested in only a subset of changes that were made to an object rather than all of them?. Everyone needs a spam filter. Well, observers can specify only those types of changes they wish to hear about through an accept list. This can be specified using the third argument to O.o() as follows:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; optAcceptList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Let’s walk through an example of how this can be used:&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;// Like earlier, a model can be a simple vanilla object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; todoModel &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;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Default&#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;completed&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;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;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// We then specify a callback for whenever mutations &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// are made to the object&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;observer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  changes&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 keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;change&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;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;change&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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 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;// Which we then observe, specifying an array of change &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// types we&#39;re interested in&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;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;delete&#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;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// without this third option, the change types provided &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// default to intrinsic types&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;todoModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Buy some milk&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// note that no changes were reported&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If however we now delete the label, notice that this type of change does get reported:&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;delete&lt;/span&gt; todoModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you don’t specify a list of accept types to O.o(), it defaults to the &amp;quot;intrinsic&amp;quot; object change types (&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;reconfigure&lt;/code&gt;, &lt;code&gt;preventExtensions&lt;/code&gt; (for when an object becoming non-extensible isn’t observable)).&lt;/p&gt;
&lt;h2 id=&quot;notifications&quot;&gt;Notifications &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#notifications&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O.o() also comes with the notion of notifications. They’re nothing like those annoying things you get on a phone, but rather useful. Notifications are similar to &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/MutationObserver&quot; rel=&quot;noopener&quot;&gt;Mutation Observers&lt;/a&gt;. They happen at the end of the micro-task. In the browser context, this is almost always going to be at the end of the current event handler.&lt;/p&gt;
&lt;p&gt;The timing is nice because generally one unit of work is finished and now observers get to do their work. It’s a nice turn-based processing model.&lt;/p&gt;
&lt;p&gt;The workflow for using a notifier looks a little like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Notifications&quot; decoding=&quot;async&quot; height=&quot;448&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/NX0q4MKDAHCyacZ1lvoJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Let’s look at an example of how notifiers might be used in practice to define custom notifications for when properties on an object are get or set. Keep an eye on the comments here:&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;// Define a simple model&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; model &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;a&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 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;// And a separate variable we&#39;ll be using for our model&#39;s &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// getter in just a moment&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Define a new property &#39;b&#39; under &#39;a&#39; with a custom&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// getter and setter&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;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;b&#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 function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _b&lt;span 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 function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;b&lt;/span&gt;&lt;span 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;// Whenever &#39;b&#39; is set on the model&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// notify the world about a specific type&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// of change being made. This gives you a huge&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// amount of control over notifications&lt;/span&gt;&lt;br /&gt;        Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNotifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;update&#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;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;b&#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;oldValue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; _b&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;// Let&#39;s also log out the value anytime it gets&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// set for kicks&lt;/span&gt;&lt;br /&gt;        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;set&#39;&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        _b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set up our observer&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;observer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    changes&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 keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;change&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;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;change&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Begin observing model.a for changes&lt;/span&gt;&lt;br /&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Notifications console&quot; decoding=&quot;async&quot; height=&quot;271&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 686px) 686px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Hw9MxpD9bTYK98aq6JrL.png?auto=format&amp;w=1372 1372w&quot; width=&quot;686&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Here we report when the value of the data properties change (&amp;quot;update&amp;quot;). Anything else the object’s implementation chooses to report (&lt;code&gt;notifier.notifyChange()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Years of experience on the web platform have taught us that a synchronous approach is the first thing you try because its the easiest to wrap your head around. The problem is it creates a fundamentally dangerous processing model. If you&#39;re writing code and say, update the property of an object, you don&#39;t really want a situation having update the property of that object could have invited some arbitrary code to go do whatever it wanted. It&#39;s not ideal to have your assumptions invalidated as you&#39;re running through the middle of a function.&lt;/p&gt;
&lt;p&gt;If you&#39;re an observer, you ideally don&#39;t want to be called if someone is in the middle of something. You don&#39;t want to be asked to go to do work on an inconsistent state of the world. End up doing a lot more error checking. Trying to tolerate a lot more bad situations and generally, its a hard model to work with. Async is harder to deal with but its a better model at the end of the day.&lt;/p&gt;
&lt;p&gt;The solution to this problem is synthetic change records.&lt;/p&gt;
&lt;h2 id=&quot;synthetic-change-records&quot;&gt;Synthetic change records &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#synthetic-change-records&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Basically, if you want to have accessors or computed properties it is your responsibility to notify when these values change. It’s a little extra work but it is designed as a sort of first-class feature of this mechanism and these notifications will be delivered with the rest of the notifications from underlying data objects. From data properties.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Synthetic change records&quot; decoding=&quot;async&quot; height=&quot;444&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/U2yz4qnKJrPd5DmiePoL.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Observing accessors and computed properties can be solved with notifier.notify - another part of O.o(). Most observation systems want some form of observing derived values. There are lots of ways to do this. O.o makes no judgement as to the &amp;quot;right&amp;quot; way. Computed properties should be accessors which &lt;em&gt;notify&lt;/em&gt; when the internal (private) state changes.&lt;/p&gt;
&lt;p&gt;Again, webdevs should expect libraries to help make notifying and various approaches to computed properties easy (and reduce boilerplate).&lt;/p&gt;
&lt;p&gt;Let’s set up the next example, which is a circle class. The idea here is that we have this circle and there’s a radius property. In this case the radius is an accessor and when its value changes it’s actually going to notify for itself that the value changed. This will be delivered with all other changes to this object or any other object. Essentially, if you’re implementing an object you want to have synthetic or computed properties or you have to pick a strategy for how this is going to work. Once you do, this will fit into your system as a whole.&lt;/p&gt;
&lt;p&gt;Skip past the code to see this working in DevTools.&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&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;var&lt;/span&gt; radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&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;var&lt;/span&gt; notifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNotifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;notifyAreaAndRadius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;update&#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;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;radius&#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;oldValue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; radius&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;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;update&#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;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;area&#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;oldValue&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;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;radius &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;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&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;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;radius&#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 function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; radius&lt;span 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 function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&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;radius &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;notifyAreaAndRadius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;area&#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 function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; 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;    &lt;span class=&quot;token punctuation&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-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      r &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;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;notifyAreaAndRadius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;observer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  changes&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 keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;change&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;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;change&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;figure&gt;
&lt;img alt=&quot;Synthetic change records console&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 690px) 690px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/9VeNfFdGdgZaBj8sf6rr.png?auto=format&amp;w=1380 1380w&quot; width=&quot;690&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;accessor-properties&quot;&gt;Accessor properties &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#accessor-properties&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A quick note on accessor properties. We mentioned earlier that only the value changes are observable for data properties. Not for computed properties or accessors. The reason is that JavaScript doesn&#39;t really have the notion of changes in value to accessors. An accessor is just a collection of functions.&lt;/p&gt;
&lt;p&gt;If you assign to an accessor JavaScript just invokes the function there and from its point of view nothing has changed. It just gave some code the opportunity to run.&lt;/p&gt;
&lt;p&gt;The problem is semantically we can look at our above assignment to the value - 5 to it. We ought to be able to know what happened here. This is actually an unsolvable problem. The example demonstrates why. There is really no way for any system to know what is meant by this because this can be arbitrary code. It can do whatever it wants in this case. It’s updating the value every time it is accessed and so asking whether it changed doesn’t make much sense.&lt;/p&gt;
&lt;h2 id=&quot;observing-multiple-objects-with-one-callback&quot;&gt;Observing multiple objects with one callback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#observing-multiple-objects-with-one-callback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another pattern possible with O.o() is the notion of a single callback observer. This allows a single callback to be used as an &amp;quot;observer&amp;quot; for lots of different objects. The callback will be delivered the full set of changes to all objects it observes at the “end of the microtask” (Note the similarity to Mutation Observers).&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Observing multiple objects with one callback&quot; decoding=&quot;async&quot; height=&quot;440&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ecy0DdsooKMHqHfoAzl0.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;large-scale-changes&quot;&gt;Large-scale changes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#large-scale-changes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Maybe you’re working on a reaaaally big app and regularly have to work with large-scale changes. Objects may wish to describe larger semantic changes which will affect lots of properties in a more compact way (instead of broadcasting tons of property changes).&lt;/p&gt;
&lt;p&gt;O.o() helps with this in the form of two specific utilities: &lt;code&gt;notifier.performChange()&lt;/code&gt; and &lt;code&gt;notifier.notify()&lt;/code&gt;, which we’ve already introduced.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Large-scale changes&quot; decoding=&quot;async&quot; height=&quot;453&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/h9YEPzJj6eEkoWhYTOwn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Let’s look at this in an example of how large-scale changes can be described where we define a Thingy object with some math utilities (multiply, increment, incrementAndMultiply). Any time a utility is used, it tells the system that a collection of work comprises a specific type of change.&lt;/p&gt;
&lt;p&gt;For example: &lt;code&gt;notifier.performChange(&#39;foo&#39;, performFooChangeFn);&lt;/code&gt;&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Thingy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MULTIPLY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;multiply&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;increment&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT_AND_MULTIPLY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;incrementAndMultiply&#39;&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 class-name&quot;&gt;Thingy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &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 function-variable function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;token punctuation&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;var&lt;/span&gt; notifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNotifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Tell the system that a collection of work comprises &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// a given changeType. e.g&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// notifier.performChange(&#39;foo&#39;, performFooChangeFn);&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// notifier.notify(&#39;foo&#39;, &#39;fooChangeRecord&#39;);&lt;/span&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;performChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; amount&lt;span 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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;object&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&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; Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT&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;incremented&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; amount&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;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;token punctuation&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;var&lt;/span&gt; notifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNotifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;performChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MULTIPLY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;*=&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;*=&lt;/span&gt; amount&lt;span 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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;object&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&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; Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MULTIPLY&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;multiplied&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; amount&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;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;incrementAndMultiply&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;incAmount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; multAmount&lt;/span&gt;&lt;span class=&quot;token punctuation&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;var&lt;/span&gt; notifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNotifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;performChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT_AND_MULTIPLY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;incAmount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;multAmount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&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;object&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&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; Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT_AND_MULTIPLY&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;incremented&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; incAmount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;multiplied&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; multAmount&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We then define two observers for our object: one which is a catch-all for changes and another which will only report back on specific accept types we’ve defined (Thingy.INCREMENT, Thingy.MULTIPLY, Thingy.INCREMENT_AND_MULTIPLY).&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;var&lt;/span&gt; observer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer2 &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;records&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;callbackCount&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 function-variable function&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;records &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callbackCount &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;span 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;observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;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;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;records &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callbackCount&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;observer2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;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;&lt;span class=&quot;token string&quot;&gt;&#39;Observer 2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;observe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// Object.observe(obj, callback, optAcceptList)&lt;/span&gt;&lt;br /&gt;  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                                    Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MULTIPLY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                                    Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INCREMENT_AND_MULTIPLY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&quot;token string&quot;&gt;&#39;update&#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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;unobserve&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unobserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&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 can now start playing with this code. Let&#39;s define a new Thingy:&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;var&lt;/span&gt; thingy &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;Thingy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&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;Observe it and then make some changes. OMG, so fun. SO many thingies!&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;// Observe thingy&lt;/span&gt;&lt;br /&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;Thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callback&lt;span 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;// Play with the methods thingy exposes&lt;/span&gt;&lt;br /&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&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 class=&quot;token comment&quot;&gt;// { a: 5, b: 7 }&lt;/span&gt;&lt;br /&gt;thingy&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 comment&quot;&gt;// { a: 5, b: 8 }&lt;/span&gt;&lt;br /&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                &lt;span class=&quot;token comment&quot;&gt;// { a: 10, b: 16 }&lt;/span&gt;&lt;br /&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                        &lt;span class=&quot;token comment&quot;&gt;// { a: 11, b: 16 }&lt;/span&gt;&lt;br /&gt;thingy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;incrementAndMultiply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// { a: 26, b: 36 }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Large-scale changes&quot; decoding=&quot;async&quot; height=&quot;356&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 688px) 688px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/QSJ7imhSFnzjxdAVa1ji.png?auto=format&amp;w=1376 1376w&quot; width=&quot;688&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Everything inside of the &amp;quot;perform function&amp;quot; is considered to be the work of “big-change”. Observers which accept “big-change” will only receive the “big-change” record. Observers which do not will receive the underlying changes resulting from the work which “perform function” did.&lt;/p&gt;
&lt;h2 id=&quot;observing-arrays&quot;&gt;Observing arrays &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#observing-arrays&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve talked for a while about observing changes to objects but what about arrays?! Great question. When someone tells me, &amp;quot;Great question.&amp;quot; I never hear their answer because I&#39;m busy congratulating myself for asking such a great question, but I digress. We have new methods for working with arrays too!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Array.observe()&lt;/code&gt; is a method that treats large-scale changes to itself - for example - splice, unshift or anything which implicitly changes it length - as a &amp;quot;splice&amp;quot; change record. Internally it uses &lt;code&gt;notifier.performChange(&amp;quot;splice&amp;quot;,...)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s an example where we observe a model &amp;quot;array&amp;quot; and similarly get back a list of changes when there are any changes to the underlying data:&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;var&lt;/span&gt; model &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;Buy some milk&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Learn to code&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Wear some plaid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; count &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;br /&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;changeRecords&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  count&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;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Array observe&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; changeRecords&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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;model&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 operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Teach Paul Lewis to code&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;model&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 operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Channel your inner Paul Irish&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Observing arrays&quot; decoding=&quot;async&quot; height=&quot;357&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 689px) 689px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/W259zu0LSyKmcSOv9DBl.png?auto=format&amp;w=1378 1378w&quot; width=&quot;689&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;performance&quot;&gt;Performance &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#performance&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The way to think about the computational performance impact of O.o() is to think about it like a read cache. Generally speaking, a cache is a great choice when (in order of importance):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The frequency of reads dominates the frequency of writes.&lt;/li&gt;
&lt;li&gt;You&#39;re able to create a cache which trades the constant amount of work involved during writes for algorithmically better performance during reads.&lt;/li&gt;
&lt;li&gt;The constant time slowdown of writes is acceptable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;O.o() is designed for use-cases like 1).&lt;/p&gt;
&lt;p&gt;Dirty-checking requires keeping a copy of all the data you&#39;re observing. This means you incur a structural memory cost to dirty-checking you just don&#39;t get with O.o(). Dirty-checking, whilst a decent stop-gap solution, is also a fundamentally leaky abstraction which can create unnecessary complexity for applications.&lt;/p&gt;
&lt;p&gt;Why? Well, dirty-checking has to run any time data &lt;em&gt;may&lt;/em&gt; have changed. There simply isn&#39;t a very robust way to do this and any approach to it has significant downsides (e.g checking on a polling interval risks visual artifacts and race conditions between code concerns). Dirty-checking also requires a global registry of observers, creating memory-leak hazards and tear-down costs O.o() avoids.&lt;/p&gt;
&lt;p&gt;Let’s take a look at some numbers.&lt;/p&gt;
&lt;p&gt;The below benchmark tests (available on &lt;a href=&quot;https://github.com/Polymer/observe-js/tree/master/benchmark&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt;) allow us to compare dirty-checking vs O.o(). They&#39;re structured as graphs of Observed-Object-Set-Size vs Number-Of-Mutations.
The general result is that dirty-checking performance is algorithmically proportional to the number of observed objects while O.o() performance is proportional to the number of mutations which were made.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dirty-checking&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Dirty checking performance&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/u0YA16bZphwvi61IzqR9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Chrome with Object.observe() switched on&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Observe performance&quot; decoding=&quot;async&quot; height=&quot;359&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Bu4TUrPE5juVVZDUlmis.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;polyfilling-objectobserve&quot;&gt;Polyfilling Object.observe() &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#polyfilling-objectobserve&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Great - so O.o() can be used in Chrome 36, but what about using it in other browsers? We’ve got you covered. Polymer’s &lt;a href=&quot;https://github.com/Polymer/observe-js&quot; rel=&quot;noopener&quot;&gt;Observe-JS&lt;/a&gt; is a polyfill for O.o() which will use the native implementation if it’s present, but otherwise polyfills it and includes some useful sugaring on top. It offers an aggregate view of the world that sums up changes and delivers a report of what has changed. Two really powerful things it exposes are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can observe paths. This means you can say, I would like to observe &amp;quot;foo.bar.baz&amp;quot; from a given object and they’ll tell you when the value at that path changed. If the path is unreachable, it considers the value undefined.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example of observing a value at a path from a given object:&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;var&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;foo&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;bar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;baz&#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;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; observer &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;PathObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;foo.bar&#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;observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;newValue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldValue&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// respond to obj.foo.bar having changed value.&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;ol start=&quot;2&quot;&gt;
&lt;li&gt;It will tell you about array splices. Array splices are basically the minimal set of splice operations you will have to perform on an array in order to transform the old version of the array into the new version of the array. This is a type of transform or different view of the array. It’s the minimum amount of work you need to do to move from the old state to the new state.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example of reporting changes to an array as a minimal set of splices:&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;var&lt;/span&gt; arr &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 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;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span 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;var&lt;/span&gt; observer &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;ArrayObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;splices&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// respond to changes to the elements of arr.&lt;/span&gt;&lt;br /&gt;  splices&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 keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    splice&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 comment&quot;&gt;// index position that the change occurred.&lt;/span&gt;&lt;br /&gt;    splice&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;removed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// an array of values representing the sequence of elements which were removed&lt;/span&gt;&lt;br /&gt;    splice&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addedCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// the number of elements which were inserted.&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;h2 id=&quot;frameworks-and-objectobserve&quot;&gt;Frameworks and Object.observe() &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#frameworks-and-objectobserve&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned, O.o() will give frameworks and libraries a huge opportunity to improve the performance of their data-binding in browsers that support the feature.&lt;/p&gt;
&lt;p&gt;Yehuda Katz and Erik Bryn from Ember confirmed that adding support for O.o() is in Ember&#39;s near-term roadmap. Angular&#39;s Misko Hervy wrote a &lt;a href=&quot;https://docs.google.com/document/d/10W46qDNO8Dl0Uye3QX0oUDPYAwaPl0qNy73TVLjd1WI/edit&quot; rel=&quot;noopener&quot;&gt;design doc&lt;/a&gt; on Angular 2.0&#39;s improved change detection. Their long term approach will be to take advantage of Object.observe() when it lands in Chrome stable, opting for &lt;a href=&quot;https://github.com/angular/watchtower.js/&quot; rel=&quot;noopener&quot;&gt;Watchtower.js&lt;/a&gt;, their own change detection approach until then. Suuuuper exciting.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O.o() is a powerful addition to the web platform which you can go out and use today.&lt;/p&gt;
&lt;p&gt;We’re hopeful that in time the feature will land in more browsers, allowing JavaScript frameworks to get performance boosts from access to native object observation capabilities. Those targeting Chrome should be able to use O.o() in Chrome 36 (and above) and the feature should also be available in a future Opera release.&lt;/p&gt;
&lt;p&gt;So, go forth and talk to the authors of JavaScript frameworks about &lt;code&gt;Object.observe()&lt;/code&gt; and how they’re planning on using it to improve the performance of data-binding in your apps. There are most definitely exciting times ahead!&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/es7-observe/#resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:observe&quot; rel=&quot;noopener&quot;&gt;Object.observe() on the Harmony wiki&lt;/a&gt;&amp;gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bocoup.com/weblog/javascript-object-observe/&quot; rel=&quot;noopener&quot;&gt;Databinding with Object.observe() by Rick Waldron&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://addyosmani.com/blog/the-future-of-data-binding-is-object-observe/&quot; rel=&quot;noopener&quot;&gt;Everything you wanted to know about Object.observe() - JSConf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://georgestefanis.com/blog/2014/03/25/object-observe-ES7.html&quot; rel=&quot;noopener&quot;&gt;Why Object.observe() is the best ES7 feature&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;With thanks to Rafael Weinstein, Jake Archibald, Eric Bidelman, Paul Kinlan and Vivian Cromwell for their input and reviews.&lt;/strong&gt;&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Synchronized cross-device mobile testing</title>
    <link href="https://web.dev/synchronized-cross-device-testing/"/>
    <updated>2013-11-25T00:00:00Z</updated>
    <id>https://web.dev/synchronized-cross-device-testing/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re a web developer targeting the multi-device web, you likely have to
test your sites and web apps across a number of different devices and
configurations. Synchronized testing can help here and is an effective way to
automatically perform the same interaction across a number of devices and
browsers at the same time.&lt;/p&gt;
&lt;p&gt;Synchronized testing can help solve two particularly time-consuming problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keeping all your devices in sync with the URL you want to test.&lt;/strong&gt; Manually
loading them on each device is so yesterday, takes longer and makes it easier
to miss out on regressions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synchronizing interactions.&lt;/strong&gt; Being able to load up a page is great for
visual testing, but for interaction testing you ideally also want to be able
to synchronize scrolls, clicks and other behaviours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thankfully if you have access to some of your target devices, there are a number
of tools aimed at improving the flow from your desktop to your mobile devices.
In this article, we will look at Ghostlab, Remote Preview, Adobe Edge Inspect
and Grunt.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;This is my desk. Well, it used to be my desk. It&amp;#x27;s now just a mobile museum.&quot; decoding=&quot;async&quot; height=&quot;598&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rfxmvUNtDJ2uOtnIblYH.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;This is my desk. Well, it used to be my desk. It&#39;s now just a mobile museum.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;tools&quot;&gt;Tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;ghostlab-mac&quot;&gt;GhostLab (Mac) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#ghostlab-mac&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt=&quot;GhostLab for Mac by Vanamco&quot; decoding=&quot;async&quot; height=&quot;517&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/tykqmqiVwnOsRrmQektw.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;GhostLab for Mac by Vanamco
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;http://vanamco.com/ghostlab/&quot; rel=&quot;noopener&quot;&gt;Ghostlab&lt;/a&gt; is a commercial Mac application ($49)
designed to synchronise testing for sites and web apps across multiple devices.
With minimum setup it allows you to simultaneously sync:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clicks&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Scrolls&lt;/li&gt;
&lt;li&gt;Form input (e.g login forms, sign-up)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes testing your site&#39;s end-to-end user experience on multiple devices
very straightforward. Once you&#39;ve opened your page in a browser on your devices,
any changes to navigation (including refreshes) cause any other connected
devices to refresh instantly. Ghostlab supports watching local directories, so
this refresh also happens when you save edits to local files, keeping everything
in sync always!&lt;/p&gt;
&lt;p&gt;I found setting up Ghostlab a painless process. To get started, download,
install and run the
&lt;a href=&quot;http://awesome.vanamco.com/downloads/ghostlab/latest/Ghostlab.dmg&quot; rel=&quot;noopener&quot;&gt;trial&lt;/a&gt; (or
full version if you&#39;re in the buying mood). You will then want to connect your
Mac and the devices you wish to test to the same Wifi network so that they&#39;re
discoverable.&lt;/p&gt;
&lt;p&gt;Once Ghostlab is running, you can either click &amp;quot;+&amp;quot; to add a URL for testing or
simply drag it from your browser&#39;s address bar. Alternatively, drag the local
folder you wish to test over into the main window and a new site entry will be
created. For this article, I&#39;m testing a live version of
&lt;a href=&quot;http://html5rocks.com/&quot; rel=&quot;noopener&quot;&gt;http://html5rocks.com&lt;/a&gt;. Cheeky, eh? ; )&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Choose a URL or local directory on your machine&quot; decoding=&quot;async&quot; height=&quot;410&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/OU4JcU5JRVLazL3tUgdf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Choose a URL or local directory on your machine
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;You can then kick-start off a new Ghostlab server by clicking the &amp;quot;&amp;gt;&amp;quot; play
button next to the name of your site. This starts a new server, available at an
IP address specific to your network (e.g
&lt;a href=&quot;http://192.168.21.43:8080/&quot; rel=&quot;noopener&quot;&gt;http://192.168.21.43:8080&lt;/a&gt;).&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Ghostlab server locally proxying content from our URL&quot; decoding=&quot;async&quot; height=&quot;598&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/hAHpmYqgtsXruQhdUsIO.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Ghostlab server locally proxying content from our URL
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Here, I&#39;ve connected up a Nexus 4 and pointed Chrome for Android to the IP
address Ghostlab gave me. That&#39;s all I have to do. Ghostlab doesn&#39;t require that
you install a dedicated client per device like some other solutions and it means
you can start testing even more quickly.&lt;/p&gt;
&lt;p&gt;Any device you connect to the Ghostlab URL will be added to the list of
connected clients in the sidebar to the right of the main Ghostlab window.
Double-clicking the device name displays additional details such as the screen
size, OS and so on. You should now be able to test navigating and synchronizing
clicks! Yay.&lt;/p&gt;
&lt;p&gt;Ghostlab is also able to display some stats about connected devices like the UA
string, viewport width and height, device pixel density, aspect ratio and more.
At any time, you can manually change the base URL you are inspecting by clicking
the settings cog next to an entry. This opens up a configuration window that
looks like the below:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Configure files to watch, HTTP headers, character sets and more.&quot; decoding=&quot;async&quot; height=&quot;508&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/a9Zxmwcg1V108mX42H2e.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Configure files to watch, HTTP headers, character sets and more.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I can now select one of my other connected devices, click on different links
around HTML5Rocks and the navigation is synchronized both on my desktop Chrome
(where I entered in the same Ghostlab URL) as well as across all of my devices.&lt;/p&gt;
&lt;p&gt;What&#39;s even better is that Ghostlab has an option allowing you to proxy all
links going through the network so that instead of a click on
&lt;a href=&quot;http://192.168.21.43:8080/www.html5rocks.com&quot; rel=&quot;noopener&quot;&gt;http://192.168.21.43:8080/www.html5rocks.com&lt;/a&gt;
navigating to
&lt;a href=&quot;http://www.html5rocks.com/performance&quot; rel=&quot;noopener&quot;&gt;www.html5rocks.com/en/performance&lt;/a&gt;
(for example), which would break the automatic cross-device refresh suffered by
other solutions, it can just translate this link into
&lt;a href=&quot;http://192.168.21.43/www.htm5rocks.com/performance&quot; rel=&quot;noopener&quot;&gt;http://192.168.21.43/www.htm5rocks.com/en/performance&lt;/a&gt;
so that navigating is completely seamless across all my devices.&lt;/p&gt;
&lt;p&gt;To enable, check &amp;quot;Load all content through Ghostlab&amp;quot; under the &amp;quot;Content Loading&amp;quot;
tab.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Ghostlab can rewrite URLs so all resources are loaded through the Ghostlab proxy. Useful for synchronizing navigations to multiple pages&quot; decoding=&quot;async&quot; height=&quot;504&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/xO5WRNa2fc9vzQLZb1QS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Ghostlab can rewrite URLs so all resources are loaded through the Ghostlab proxy. Useful for synchronizing navigations to multiple pages
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Seeing it in action:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Synchronized testing of an Android, Windows 8 and Firefox OS phone with Ghostlab&quot; decoding=&quot;async&quot; height=&quot;598&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/eQE7t4VygF5xq7CJpoQV.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Synchronized testing of an Android, Windows 8 and Firefox OS phone with Ghostlab
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Ghostlab is capable of loading any number of sites or windows across any
supported browser. This doesn&#39;t just let you test your site at different
resolutions, but how your code behaves on different browsers and platforms. Yay!&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Synchronizing scroll, clicks and navigation across all of the test devices&quot; decoding=&quot;async&quot; height=&quot;351&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 623px) 623px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/EkUMeViMnNTjdRLrVKQG.gif?auto=format&amp;w=1246 1246w&quot; width=&quot;623&quot; /&gt;
  &lt;figcaption&gt;Synchronizing scroll, clicks and navigation across all of the test devices
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Ghostlab allows you to configure the setup for the project workspace you&#39;re
previewing and you can specify whether you would like changes to the directory
to be watched and refreshed when detected. This means changes cause all
connected clients to be refreshed. No more manual refreshes!&lt;/p&gt;
&lt;p&gt;You may be wondering what else Ghostlab can help with. Whilst it&#39;s certainly not
a swiss-army knife, it also supports remote code inspection on connected
devices. Through the main interface, double-clicking on any device name should
bring up a &amp;quot;debug&amp;quot; option which will launch a version of the &lt;a href=&quot;http://devtools.chrome.com/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt; for
you to play around with.&lt;/p&gt;
&lt;p&gt;Ghostlab makes this possible via the bundled &lt;a href=&quot;http://people.apache.org/~pmuellr/weinre/docs/latest/&quot; rel=&quot;noopener&quot;&gt;Weinre&lt;/a&gt; remote web inspector, which
lets you debug scripts and tweak styles on connected devices. Similar to the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/remote-debugging/&quot; rel=&quot;noopener&quot;&gt;remote debugging&lt;/a&gt; experience available for Chrome for Android, you can select elements, run some
performance profiling and debug scripts.&lt;/p&gt;
&lt;p&gt;All in all, I was impressed with how quickly I was able to use Ghostlab for
everyday testing across devices. If you&#39;re a freelancer, you might find the cost
of the commercial license a little high (see below for more options).  However,
I&#39;m happy to recommend Ghostlab otherwise.&lt;/p&gt;
&lt;h3 id=&quot;adobe-edge-inspect-cc-mac,-windows&quot;&gt;Adobe Edge Inspect CC (Mac, Windows) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#adobe-edge-inspect-cc-mac,-windows&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Adobe&amp;#x27;s Creative Cloud subscription includes Edge Inspect&quot; decoding=&quot;async&quot; height=&quot;512&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8U2DXCGXtItfi82pNOv1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Adobe&#39;s Creative Cloud subscription includes Edge Inspect
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Adobe Edge Inspect is part of the Adobe Creative Cloud subscription package, but
also comes available as a free trial. It allows you to drive multiple iOS and
Android devices with Chrome (via the Edge Inspector Chrome extension), so that
if you browse to a particular URL all of your connected devices stay in sync.&lt;/p&gt;
&lt;p&gt;To get set up, first sign up for an &lt;a href=&quot;http://creative.adobe.com/&quot; rel=&quot;noopener&quot;&gt;Adobe Creative
Cloud&lt;/a&gt; account or login to an existing account if
you already have one.  Next, download and install &lt;a href=&quot;https://creative.adobe.com/inspect&quot; rel=&quot;noopener&quot;&gt;Edge
Inspect&lt;/a&gt; from Adobe.com (available for Mac
and Windows at present, but not Linux - sorry!).  Note the
&lt;a href=&quot;http://forums.adobe.com/docs/DOC-2535&quot; rel=&quot;noopener&quot;&gt;docs&lt;/a&gt; for Edge Inspect are useful to
keep at hand.&lt;/p&gt;
&lt;p&gt;Once installed, you&#39;ll want to get the &lt;a href=&quot;http://www.adobe.com/go/edgeinspect_chrome&quot; rel=&quot;noopener&quot;&gt;Edge inspect
extension&lt;/a&gt; for Chrome so that you
can synchronize browsing between connected devices.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The Edge Inspect CC Chrome Extension&quot; decoding=&quot;async&quot; height=&quot;214&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 325px) 325px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/cae6RFljZG7BS6zuNMrK.png?auto=format&amp;w=650 650w&quot; width=&quot;325&quot; /&gt;
  &lt;figcaption&gt;The Edge Inspect CC Chrome Extension
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;You will also need to install an Edge Inspect client on each device you wish to
sync actions with. Thankfully clients are available for
&lt;a href=&quot;http://www.adobe.com/go/edgeinspect_ios&quot; rel=&quot;noopener&quot;&gt;iOS&lt;/a&gt;,
&lt;a href=&quot;http://www.adobe.com/go/edgeinspect_android&quot; rel=&quot;noopener&quot;&gt;Android&lt;/a&gt; and
&lt;a href=&quot;http://www.adobe.com/go/edgeinspect_amazon&quot; rel=&quot;noopener&quot;&gt;Kindle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the installation process behind us, we can now start inspecting our pages.
You&#39;ll need to make sure all your devices are connected to the same network for
this to work.&lt;/p&gt;
&lt;p&gt;Start up Edge Inspect on your desktop, the Edge Inspect extension in Chrome and
then the app on your devices (see below):&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Connecting a device up to the Edge Inspect extension&quot; decoding=&quot;async&quot; height=&quot;451&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 605px) 605px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RrPK7JYnuiGoC77xcj1Q.png?auto=format&amp;w=1210 1210w&quot; width=&quot;605&quot; /&gt;
  &lt;figcaption&gt;Connecting a device up to the Edge Inspect extension
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;We can now navigate to a site like HTML5Rocks.com on desktop and our mobile
device will automatically navigate to the same page.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Driving navigation of a URL across multiple connected devices&quot; decoding=&quot;async&quot; height=&quot;598&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/XAvQlt7WHiuPELPsHJKv.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Driving navigation of a URL across multiple connected devices
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In the extension, you&#39;ll also now see your device listed with a &amp;lt;&amp;gt; symbol next
to it as in the screenshot below. Clicking this will launch an instance of Weinre allowing you to inspect and debug your page.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Connected devices appear with a &amp;lt;&amp;gt; symbol next to them, which can be used to launch the Weinre debugger&quot; decoding=&quot;async&quot; height=&quot;549&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rWsxtUuWj17uJA92rrzG.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Connected devices appear with a &lt;&gt; symbol next to them, which can be used to launch the Weinre debugger
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Weinre is a DOM viewer and console, and lacks features from the Chrome DevTools like JavaScript debugging, profiling, and network waterfall. While it is the bare minimum of developer tooling, it&#39;s useful for sanity-checking DOM and JavaScript state.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Debugging with Weinre&quot; decoding=&quot;async&quot; height=&quot;456&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/vGeQ7zaldu9MPJCu8iFf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Debugging with Weinre
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The Edge Inspect extension also supports generating screenshots from connected devices with ease. Useful for layout testing or just getting captures of your page to share with others.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshot generation with Edge Inspect&quot; decoding=&quot;async&quot; height=&quot;296&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 547px) 547px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Nc1Lf9Fv72IDRWD8o2v1.png?auto=format&amp;w=1094 1094w&quot; width=&quot;547&quot; /&gt;
  &lt;figcaption&gt;Screenshot generation with Edge Inspect
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For developers already paying for CC, Edge Inspect is a great solution. It does
however come with a few caveats such as each device requiring a dedicated client
to be installed and a little extra setup work that you may not find with an
alternative like Ghostlab.&lt;/p&gt;
&lt;h3 id=&quot;remote-preview-mac,-windows,-linux&quot;&gt;Remote Preview (Mac, Windows, Linux) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#remote-preview-mac,-windows,-linux&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://viljamis.com/blog/2012/remote-preview/&quot; rel=&quot;noopener&quot;&gt;Remote Preview&lt;/a&gt; is an open
source tool where you host HTML pages and content that you can display on
multiple devices.&lt;/p&gt;
&lt;p&gt;Remote preview executes an XHR call at an interval of every 1100ms to check if a
URL in a configuration file has changed. If it finds that it has, the script
updates the src attribute of an iframe loaded into the page for each device,
loading the page into it. If there are no changes detected, the script will
continue polling until a change is made.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Synchronized URL testing across 27+ devices&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/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ekGQXOwVV8IPlwEkwVDm.gif?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Synchronized URL testing across 27+ devices
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is great for chaining devices together and easily changing a URL across all
of them. To get started:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/viljamis/Remote-Preview&quot; rel=&quot;noopener&quot;&gt;Download&lt;/a&gt; Remote Preview and move all of the files for it into a locally accessible server. This can be Dropbox,
a development server or something else.&lt;/li&gt;
&lt;li&gt;Load up &amp;quot;index.html&amp;quot; from this download on all of your target devices. This
page will be used as a driver and will load up the page you want to test using
an iframe.&lt;/li&gt;
&lt;li&gt;Edit &amp;quot;url.txt&amp;quot; (included in the download and now served on your server) with
the URL you wish to preview. Save this file.&lt;/li&gt;
&lt;li&gt;Remote Preview will notice that the url.txt file has changed and will refresh
all connected devices to load up your URL.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Whilst a lo-fi solution, Remote Preview is free and works.&lt;/p&gt;
&lt;h3 id=&quot;grunt-live-reload-mac,-windows,-linux&quot;&gt;Grunt + Live-Reload (Mac, Windows, Linux) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#grunt-live-reload-mac,-windows,-linux&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://gruntjs.com/&quot; rel=&quot;noopener&quot;&gt;Grunt&lt;/a&gt; (and &lt;a href=&quot;http://yeoman.io/&quot; rel=&quot;noopener&quot;&gt;Yeoman&lt;/a&gt;) are command-line
tools used for scaffolding and building projects on the front-end. If you&#39;re
already using these tools and have live-reload setup, it&#39;s easy to update your
workflow to enable cross-device testing where each change you make in your
editor causes a reload in any of the devices you&#39;ve opened up your local app on.&lt;/p&gt;
&lt;p&gt;You&#39;re probably used to using &lt;code&gt;grunt server&lt;/code&gt;. When run from the root directory
of your project, it watches for any changes to your source files and
automatically refreshes the browser window. This is thanks to the
grunt-contrib-watch task which we run as part of the server.&lt;/p&gt;
&lt;p&gt;If you happen to have used Yeoman to scaffold out your project, it will have
created a Gruntfile with everything you need to get live-reload working on your
desktop. To get it functioning cross-device, you just need to change one
property, which is the &lt;code&gt;hostname&lt;/code&gt; (on your desktop). It should be listed under
&lt;code&gt;connect&lt;/code&gt;. If you notice &lt;code&gt;hostname&lt;/code&gt; is set to &lt;code&gt;localhost&lt;/code&gt; just change it to
0.0.0.0. Next run &lt;code&gt;grunt server&lt;/code&gt; and as usual, a new window should open
displaying a preview of your page. The URL will probably look like
&lt;a href=&quot;http://localhost:9000/&quot; rel=&quot;noopener&quot;&gt;http://localhost:9000&lt;/a&gt; (9000 is the port).&lt;/p&gt;
&lt;p&gt;Fire up a new tab or terminal and use &lt;code&gt;ipconfig | grep inet&lt;/code&gt; to discover your
system&#39;s internal IP. It may look like &lt;code&gt;192.168.32.20&lt;/code&gt;. The last step is to open
up a browser like Chrome on the device you would like to synchronize livereloads
to and type in this IP address followed by the port number from earlier. i.e
&lt;code&gt;192.169.32.20:9000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s it! Live-reload should now cause any edits you make to source files on
your desktop to trigger reloads in both your desktop browser &lt;em&gt;and&lt;/em&gt; the browser
on your mobile device. Awesome!&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Saved edits on desktop now trigger a live-reload in your desktop browser as well as mobile browsers on devices with the same URL&quot; decoding=&quot;async&quot; height=&quot;598&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lpWoeIDEbXAI917RMrii.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Saved edits on desktop now trigger a live-reload in your desktop browser as well as mobile browsers on devices with the same URL
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Cross-device live-reload in action. Each edit/save gives you a real-time for of your current page, great for responsive design testing.&quot; decoding=&quot;async&quot; height=&quot;413&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 735px) 735px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MzRPsvU8WIadYdcUf81K.gif?auto=format&amp;w=1470 1470w&quot; width=&quot;735&quot; /&gt;
  &lt;figcaption&gt;Cross-device live-reload in action. Each edit/save gives you a real-time for of your current page, great for responsive design testing.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Yeoman also has a &lt;a href=&quot;https://github.com/yeoman/generator-mobile&quot; rel=&quot;noopener&quot;&gt;Mobile generator&lt;/a&gt;
available which makes setting this workflow up a breeze.&lt;/p&gt;
&lt;h3 id=&quot;emmet-livestyle&quot;&gt;Emmet LiveStyle &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#emmet-livestyle&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Emmet LiveStyle is a browser and editor plugin that brings live CSS editing to
your development workflow. It is currently available for Chrome, Safari and
Sublime Text and supports bi-directional (editor to browser and vice-versa)
editing.&lt;/p&gt;
&lt;p&gt;Emmet LiveStyle doesn&#39;t force a complete browser refresh when you make changes,
but instead pushes CSS edits across the DevTools remote debugging protocol. What
this means is that you can see changes made in your desktop editor in any
connected version of Chrome, whether it be on desktop Chrome or Chrome for
Android.&lt;/p&gt;
&lt;p&gt;LiveStyle has what it calls &amp;quot;multi-view mode&amp;quot;, which is ideal for testing and
tweaking responsive designs across windows and devices. In multi-view mode, all
editor updates are applied to all windows as are DevTools updates for the same
page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With the LiveStyle package installed, to get started with live CSS editing:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start up Sublime Text and open up a CSS file in a project&lt;/li&gt;
&lt;li&gt;Start Chrome and go to the page with the CSS you would like to edit&lt;/li&gt;
&lt;li&gt;Open DevTools and go to the LiveStyle panel. Check the &amp;quot;Enable LiveStyle&amp;quot;
option. Note: DevTools will need to be kept open during your live editing
session for each window in order for style updates to be applied.&lt;/li&gt;
&lt;li&gt;When this has been enabled, a list of stylesheets will be displayed on the
left and a list of your editor files on the right. Select the editor file to be
associated with the browser. That&#39;s it! Boom.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now the list of editor files will be automatically updated when you edit,
create, open or close files.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Changes to CSS in Sublime being instantly patched across different browser windows and an emulator.&quot; decoding=&quot;async&quot; height=&quot;586&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 781px) 781px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/LHsl7cCjGBztNAN77XKr.gif?auto=format&amp;w=1562 1562w&quot; width=&quot;781&quot; /&gt;
  &lt;figcaption&gt;Changes to CSS in Sublime being instantly patched across different browser windows and an emulator. 
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#conclusions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cross-device testing is still a new and fast moving space with many new
contenders in development. Thankfully there exist a number of free and
commercial tools for assuring your compatibility and testing across a wide
number of device sets.&lt;/p&gt;
&lt;p&gt;That said, there&#39;s still a lot of potential for improvement in this area and we
would encourage you to think about how the tooling for testing across devices
can be further improved. Anything that reduces setup time and improves your
cross-device workflow is a win.&lt;/p&gt;
&lt;h3 id=&quot;issues&quot;&gt;Issues &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#issues&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Perhaps the largest issues I ran into during testing with these tools was
devices regularly going to sleep. This isn&#39;t a deal-breaker, but does get
annoying after a while. Where possible it&#39;s a good idea to set your devices to
not sleep as a workaround, however, keep in mind that this can drain your
battery unless you&#39;re always plugged in.&lt;/p&gt;
&lt;p&gt;I didn&#39;t personally run into any major issues with GhostLab. At $49 some may
find the price a little steep; however, keep in mind if you&#39;re using it
regularly it more or less pays for itself. One of the nicest things about the
setup was not having to worry about installing and managing a client per target
device. The same URL worked everywhere.&lt;/p&gt;
&lt;p&gt;With Adobe Edge Inspect, I found having to install and use specific clients on
each device a little bit tedious. I also found it didn&#39;t consistently refresh
all of the clients connected up, meaning I had to do this myself from the Chrome
extension. It also requires a subscription to Creative Cloud and is limited to
loading up sites in the client rather than in a selected browser on your
devices. This may limit your ability to accurately test.&lt;/p&gt;
&lt;p&gt;Remote Preview functioned as advertised, but is extremely lightweight. This
means for anything more than refreshing your site across devices, you&#39;ll need a
more advanced tooling option. It won&#39;t for example, synchronize clicks or
scrolls.&lt;/p&gt;
&lt;h2 id=&quot;recommendations&quot;&gt;Recommendations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/synchronized-cross-device-testing/#recommendations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re looking for a free cross-platform solution to get you started, I
recommend using Remote Preview. For those working in a company looking for a
paid-for solution, GhostLab has been consistently excellent in my experience but
is only available for the Mac. For Windows users, Adobe Edge Inspect is your
best call and minus some quirks, does generally get the job done.&lt;/p&gt;
&lt;p&gt;Grunt and LiveStyle are also excellent for augmenting your live iteration during
development.&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Building web apps with Yeoman and Polymer</title>
    <link href="https://web.dev/yeoman/"/>
    <updated>2013-10-10T00:00:00Z</updated>
    <id>https://web.dev/yeoman/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Allo’ Allo’. Anyone writing a web app knows how important it is to keep oneself productive. It&#39;s a challenge when you have to worry about tedious tasks like finding the right boilerplate, setting up a development and testing workflow and minifying and compressing all your sources.&lt;/p&gt;
&lt;p&gt;Fortunately modern front-end tooling can help automate much of this, leaving you to focus on writing a kick-ass app. This article will show you how to use &lt;a href=&quot;http://yeoman.io/&quot; rel=&quot;noopener&quot;&gt;Yeoman&lt;/a&gt;, a workflow of tools for web apps to streamline creating apps using &lt;a href=&quot;http://polymer-project.org/&quot; rel=&quot;noopener&quot;&gt;Polymer&lt;/a&gt;, a library of polyfills and sugar for developing apps using &lt;a href=&quot;http://html5-demos.appspot.com/static/webcomponents/index.html#1&quot; rel=&quot;noopener&quot;&gt;Web Components&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Yeoman&quot; decoding=&quot;async&quot; height=&quot;741&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KpmUdvaxPewJIqbzdH8m.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; If you&#39;re new to Web Components, I recommend reading the fantastic &lt;a href=&quot;http://www.polymer-project.org/getting-started.html&quot;&gt;docs&lt;/a&gt; about the web platform features they provide. Guides on how to use them via Polymer are available for &lt;a href=&quot;http://www.polymer-project.org/platform/custom-elements.html&quot;&gt;Custom Elements&lt;/a&gt;, &lt;a href=&quot;http://www.polymer-project.org/platform/shadow-dom.html&quot;&gt;Shadow DOM&lt;/a&gt;, &lt;a href=&quot;http://www.polymer-project.org/platform/html-imports.html&quot;&gt;HTML Imports&lt;/a&gt; and more. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;meet-yo,-grunt-and-bower&quot;&gt;Meet Yo, Grunt and Bower &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#meet-yo,-grunt-and-bower&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yeoman is a man in a hat with three tools for improving your productivity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://yeoman.io/&quot; rel=&quot;noopener&quot;&gt;yo&lt;/a&gt; is a scaffolding tool that offers an ecosystem of framework-specific scaffolds, called generators that can be used to perform some of the tedious tasks I mentioned earlier.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gruntjs.com/&quot; rel=&quot;noopener&quot;&gt;grunt&lt;/a&gt; is used to build, preview and test your project, thanks to help from tasks curated by the Yeoman team and &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib&quot; rel=&quot;noopener&quot;&gt;grunt-contrib&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bower.io/&quot; rel=&quot;noopener&quot;&gt;bower&lt;/a&gt; is used for dependency management, so that you no longer have to manually download and manage your scripts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With just a command or two, Yeoman can write boilerplate code for your app (or individual pieces like Models), compile your Sass, minimize and concatenate your CSS, JS, HTML and images and fire up a simple web server in your current directory. It can also run your unit tests and more.&lt;/p&gt;
&lt;p&gt;You can install generators from &lt;a href=&quot;http://npmjs.org/&quot; rel=&quot;noopener&quot;&gt;Node Packaged Modules&lt;/a&gt; (npm) and there are over &lt;a href=&quot;http://yeoman.io/community-generators.html&quot; rel=&quot;noopener&quot;&gt;220 generators&lt;/a&gt; now available, many of which have been written by the open-source community. Popular generators include &lt;a href=&quot;https://github.com/yeoman/generator-angular&quot; rel=&quot;noopener&quot;&gt;generator-angular&lt;/a&gt;, &lt;a href=&quot;https://github.com/yeoman/generator-backbone&quot; rel=&quot;noopener&quot;&gt;generator-backbone&lt;/a&gt; and &lt;a href=&quot;https://github.com/yeoman/generator-ember&quot; rel=&quot;noopener&quot;&gt;generator-ember&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Yeoman homepage&quot; decoding=&quot;async&quot; height=&quot;583&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/CLISe3G54Uv0ivqJq9zD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With a recent version of &lt;a href=&quot;http://nodejs.org/&quot; rel=&quot;noopener&quot;&gt;Node.js&lt;/a&gt; installed, head to your nearest terminal and run:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -g yo&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;That&#39;s it! You now have Yo, Grunt and Bower and can run them directly from the command-line. Here’s the output of running &lt;code&gt;yo&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Yeoman installation&quot; decoding=&quot;async&quot; height=&quot;358&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c5HA1pi9f2c38SrlJykb.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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; If you’re interested in reading more about how to use Yeoman to write a complete application using other frameworks like Backbone, you may be interested in &lt;a href=&quot;http://net.tutsplus.com/tutorials/javascript-ajax/building-apps-with-the-yeoman-workflow/&quot;&gt;Building Apps With The Yeoman Workflow&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;polymer-generator&quot;&gt;Polymer Generator &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#polymer-generator&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier, Polymer is a library of polyfills and sugar which enables the use of Web Components in modern browsers. The project allows developers to build apps using the platform of tomorrow and inform the W3C of places where in-flight specifications can be further improved.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Polymer generator hompage&quot; decoding=&quot;async&quot; height=&quot;597&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/KdEguasjtibQOiOGkp2h.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yeoman/generator-polymer&quot;&gt;generator-polymer&lt;/a&gt; is a new generator that helps you scaffold out Polymer apps using Yeoman, letting you easily create and customize Polymer (custom) elements via the command line, and import them using HTML Imports. This saves you time by writing the boilerplate code for you.&lt;/p&gt;
&lt;p&gt;Next, install Polymer’s generator by running:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; generator-polymer -g&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;That&#39;s it.  Now your app has Web Component super-powers!&lt;/p&gt;
&lt;p&gt;Our newly installed generator has a few specific bits you’ll have access to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;polymer:element&lt;/code&gt; is used to scaffold out new individual Polymer elements. For example: &lt;code&gt;yo polymer:element carousel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;polymer:app&lt;/code&gt; is used to scaffold your initial index.html, a Gruntfile.js containing build-time configuration for your project as well as Grunt tasks and a folder structure recommended for the project. It will also give you the option of using Sass Bootstrap for your project’s styles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;lets-build-a-polymer-app&quot;&gt;Let’s build a Polymer app &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#lets-build-a-polymer-app&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re going to build a simple blog using some custom Polymer elements and our new generator.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Polymer app&quot; decoding=&quot;async&quot; height=&quot;664&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/sYx7sIeA15FBWX5GkxYO.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To begin, go to the terminal, make a new directory and cd into it using &lt;code&gt;mkdir my-new-project &amp;amp;&amp;amp; cd $_&lt;/code&gt;. You can now kick-start your Polymer app by running:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ yo polymer&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Polymer app building&quot; decoding=&quot;async&quot; height=&quot;338&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lFnx4GQEyNi3ObAqPdWK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This gets the latest version of Polymer from Bower and scaffolds out an index.html, directory structure and Grunt tasks for your workflow. Why not grab a coffee while we wait for the app to finish getting ready?&lt;/p&gt;
&lt;p&gt;Okay, so next we can run &lt;code&gt;grunt server&lt;/code&gt; to preview what the app looks like:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Grunt server&quot; decoding=&quot;async&quot; height=&quot;478&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8y5tiYtk2hck0e4Tn27X.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The server supports LiveReload, meaning you can fire up a text editor, edit a custom element and the browser will reload on save. This gives you a nice real-time view of your app’s current state.&lt;/p&gt;
&lt;p&gt;Next, let&#39;s create a new Polymer element to represent a Blog post.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ yo polymer:element post&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Create post element&quot; decoding=&quot;async&quot; height=&quot;389&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/5B877XHV5vMrHQu2Y9vc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Yeoman asks us a few questions such as whether we would like to include a constructor or use an HTML Import to include the post element in &lt;code&gt;index.html&lt;/code&gt;. Let&#39;s say No to the first two options for now and leave the third option blank.&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 we say &#39;yes&#39; to the second question, the generator imports post.html and includes it in index.html. It also declares &lt;code&gt;&amp;lt;post-element&amp;gt;&lt;/code&gt; so the element renders on page load. &lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ yo polymer:element post&lt;br /&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; Would you like to include &lt;span class=&quot;token assign-left variable&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;? No&lt;br /&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; Import to your index.html using HTML imports? No&lt;br /&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; Import other elements into this one? &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e.g &lt;span class=&quot;token string&quot;&gt;&#39;another_element.html&#39;&lt;/span&gt; or leave blank&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    create app/elements/post.html&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This creates a new Polymer element in the &lt;code&gt;/elements&lt;/code&gt; directory named post.html:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;polymer-element&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;post-element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;token attr-name&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;        &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@host&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I&#39;m &lt;span class=&quot;token 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;post-element&lt;span class=&quot;token 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;. This is my Shadow DOM.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;Polymer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;post-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;//applyAuthorStyles: true,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;//resetStyleInheritance: true,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;enteredView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;leftView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;attributeChanged&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;attrName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldVal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newVal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;polymer-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boilerplate code for your &lt;a href=&quot;http://www.polymer-project.org/platform/custom-elements.html&quot; rel=&quot;noopener&quot;&gt;custom element&lt;/a&gt;, allowing you to use a custom DOM element type in your page (e.g &lt;code&gt;&amp;lt;post-element&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;http://www.html5rocks.com/tutorials/webcomponents/template/&quot; rel=&quot;noopener&quot;&gt;template tag&lt;/a&gt; for ‘native’ client-side templating and sample &lt;a href=&quot;http://www.html5rocks.com/tutorials/webcomponents/shadowdom-201/&quot; rel=&quot;noopener&quot;&gt;scoped styles&lt;/a&gt; for encapsulating the styles of your element&lt;/li&gt;
&lt;li&gt;Element &lt;a href=&quot;http://www.polymer-project.org/polymer.html#element-declaration&quot; rel=&quot;noopener&quot;&gt;registration&lt;/a&gt; boilerplate and &lt;a href=&quot;http://www.polymer-project.org/polymer.html#lifecyclemethods&quot; rel=&quot;noopener&quot;&gt;lifecycle events&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;working-with-a-real-source-of-data&quot;&gt;Working with a real source of data &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#working-with-a-real-source-of-data&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our blog will need a place to write and read new posts. To demonstrate working with a real data service, we’re going to use the &lt;a href=&quot;https://developers.google.com/google-apps/spreadsheets/&quot; rel=&quot;noopener&quot;&gt;Google Apps Spreadsheets API&lt;/a&gt;. This allows us to easily read in the content of any spreadsheet created using Google Docs.&lt;/p&gt;
&lt;p&gt;Let’s get this set up:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In your browser (for these steps, Chrome is recommended) open up &lt;a href=&quot;https://docs.google.com/spreadsheet/ccc?key=0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc#gid=0&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; Google Docs Spreadsheet. It contains sample post data under the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ID&lt;/li&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Author&lt;/li&gt;
&lt;li&gt;Content&lt;/li&gt;
&lt;li&gt;Date&lt;/li&gt;
&lt;li&gt;Keywords&lt;/li&gt;
&lt;li&gt;E-mail (of the author)&lt;/li&gt;
&lt;li&gt;Slug (for your post’s slug URL)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the &lt;strong&gt;File&lt;/strong&gt; menu and select &lt;strong&gt;Make a copy&lt;/strong&gt; to create your own copy of the spreadsheet. You are free to edit the content at your leisure, adding or removing posts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the &lt;strong&gt;File&lt;/strong&gt; menu once again and select &lt;strong&gt;Publish to the web&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;start publishing&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;Get a link to the published data&lt;/strong&gt;, from the last text box, copy the &lt;strong&gt;key&lt;/strong&gt; portion of the URL provided. It looks like this: &lt;a href=&quot;https://docs.google.com/spreadsheet/ccc?key=0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc#gid=0&quot; rel=&quot;noopener&quot;&gt;https://docs.google.com/spreadsheet/ccc?key=0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc#gid=0&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the &lt;strong&gt;key&lt;/strong&gt; into the following URL where it says &lt;strong&gt;your-key-goes-here&lt;/strong&gt;: &lt;strong&gt;&lt;a href=&quot;https://spreadsheets.google.com/feeds/list/your-key-goes-here/od6/public/values?alt=json-in-script&amp;amp;callback=&quot; rel=&quot;noopener&quot;&gt;https://spreadsheets.google.com/feeds/list/your-key-goes-here/od6/public/values?alt=json-in-script&amp;amp;callback=&lt;/a&gt;&lt;/strong&gt;. An example using the key above might look like &lt;a href=&quot;https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script&quot; rel=&quot;noopener&quot;&gt;https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can paste the URL into your browser and navigate to it to view the JSON version of your blog content. Take note of the URL then spend a little time reviewing the format of this data as you will need to iterate over it in order to display it on screen later.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The JSON output in your browser may look a little daunting, but don’t worry!. We’re really only interested in the data for your posts.&lt;/p&gt;
&lt;p&gt;The Google Spreadsheets API outputs each of the fields in your blog spreadsheet with a special prefix &lt;code&gt;post.gsx$&lt;/code&gt;. For example: &lt;code&gt;post.gsx$title.$t&lt;/code&gt;, &lt;code&gt;post.gsx$author.$t&lt;/code&gt;, &lt;code&gt;post.gsx$content.$t&lt;/code&gt; and so on. When we iterate over each “row” in our JSON output, we’ll reference these fields to get back the relevant values for each post.&lt;/p&gt;
&lt;p&gt;You can now edit your newly scaffolded post element to &lt;a href=&quot;http://www.polymer-project.org/docs/polymer/databinding.html&quot; rel=&quot;noopener&quot;&gt;bind&lt;/a&gt; portions of markup to the data in your spreadsheet. To do so, we introduce an attribute &lt;code&gt;post&lt;/code&gt;, which will read for the post title, author, content and other fields we created earlier. The &lt;code&gt;selected&lt;/code&gt; attribute (which we will populate later) is used to only show a post if a user navigates to the correct slug for it.&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;polymer-element&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;post-element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post selected&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;        &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@host&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;col-lg-4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post.gsx$slug.$t === selected]]&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#[[post.gsx$slug.$t]]&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;                [[post.gsx$title.$t  ]]&lt;br /&gt;                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;By [[post.gsx$author.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token 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;[[post.gsx$content.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token 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;Published on: [[post.gsx$date.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Keywords: [[post.gsx$keywords.$t]]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;Polymer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;post-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;enteredView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;leftView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;attributeChanged&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;attrName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldVal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newVal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;polymer-element&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;Next, let&#39;s create a blog element which contains both a collection of posts and the layout for your blog by running &lt;code&gt;yo polymer:element blog&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ yo polymer:element blog&lt;br /&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; Would you like to include &lt;span class=&quot;token assign-left variable&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;? No&lt;br /&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; Import to your index.html using HTML imports? Yes&lt;br /&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; Import other elements into this one? &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e.g &lt;span class=&quot;token string&quot;&gt;&#39;another_element.html&#39;&lt;/span&gt; or leave blank&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; post.html&lt;br /&gt;&lt;br /&gt;    create app/elements/blog.html&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This time we import the blog into index.html using &lt;a href=&quot;http://www.polymer-project.org/platform/html-imports.html&quot; rel=&quot;noopener&quot;&gt;HTML imports&lt;/a&gt; as we would like it to appear in the page. For the third prompt specifically, we specify &lt;code&gt;post.html&lt;/code&gt; as the element we would like to include.&lt;/p&gt;
&lt;p&gt;As before, a new element file is created (blog.html) and added to /elements, this time importing post.html and including &lt;code&gt;&amp;lt;post-element&amp;gt;&lt;/code&gt; within the template tag:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post.html&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;polymer-element&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;blog-element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;token attr-name&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;        &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@host&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I&#39;m &lt;span class=&quot;token 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;blog-element&lt;span class=&quot;token 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;. This is my Shadow DOM.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;post-element&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;post-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;Polymer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;blog-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;//applyAuthorStyles: true,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;//resetStyleInheritance: true,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;enteredView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;leftView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;attributeChanged&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;attrName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldVal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newVal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;polymer-element&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 we asked for the blog element to be imported using &lt;a href=&quot;http://www.polymer-project.org/platform/html-imports.html&quot; rel=&quot;noopener&quot;&gt;HTML imports&lt;/a&gt; (a way to include and reuse HTML documents in other HTML documents) to our index, we can also verify that it has been correctly added to the document &lt;code&gt;&amp;lt;head&amp;gt;&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 doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;doctype&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;http-equiv&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;X-UA-Compatible&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;IE=edge&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;title&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;title&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;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;description&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;&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;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&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;styles/main.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- build:js scripts/vendor/modernizr.js --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;bower_components/modernizr/modernizr.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- endbuild --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Place your HTML imports here --&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;elements/blog.html&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;head&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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token 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;hero-unit&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;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;90%&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;br /&gt;                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;blog-element&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;blog-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;        document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;WebComponentsReady&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// Perform some behaviour&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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- build:js scripts/vendor.js --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;bower_components/polymer/polymer.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- endbuild --&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;body&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;html&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;Fantastic.&lt;/p&gt;
&lt;h3 id=&quot;adding-dependencies-using-bower&quot;&gt;Adding dependencies using Bower &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#adding-dependencies-using-bower&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, let’s edit our element to use the &lt;a href=&quot;https://github.com/Polymer/polymer-elements/tree/master/polymer-jsonp&quot; rel=&quot;noopener&quot;&gt;Polymer JSONP&lt;/a&gt; utility element to read in posts.json. You can either get the adapter by git cloning the repository or installing &lt;code&gt;polymer-elements&lt;/code&gt; via Bower by running &lt;code&gt;bower install polymer-elements&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Bower dependencies&quot; decoding=&quot;async&quot; height=&quot;379&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rLhfQZTcemXKjcvtwVNo.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Once you have the utility, you’ll need to include it as an import in your blog.html element with:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;../bower_components/polymer-jsonp/polymer-jsonp.html&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;Next, include the tag for it and supply the &lt;code&gt;url&lt;/code&gt; to our blog posts spreadsheet from earlier, adding &lt;code&gt;&amp;amp;callback=&lt;/code&gt; to the end:&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;polymer-jsonp&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://spreadsheets.google.com/feeds/list/your-key-value/od6/public/values?alt=json-in-script&amp;amp;callback=&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[posts]]&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;polymer-jsonp&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;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you find yourself stuck, feel free to use my spreadsheet &lt;a href=&quot;https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script&quot;&gt;https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script&lt;/a&gt; as the value of your URL so you can continue with the tutorial. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;With this in place, we can now add templates to iterate over our spreadsheet once it has been read in. The first outputs a table of contents, with a linked title for a post pointing at the slug for it.&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 comment&quot;&gt;&amp;lt;!-- Table of contents --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post in posts.feed.entry]]&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#[[post.gsx$slug.$t]]&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;[[post.gsx$title.$t]]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The second renders one instance of &lt;code&gt;post-element&lt;/code&gt; for each entry found, passing the post content through to it accordingly. Notice that we’re passing through a &lt;code&gt;post&lt;/code&gt; attribute representing the post content for a single spreadsheet row and a &lt;code&gt;selected&lt;/code&gt; attribute which we will populate with a route.&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 comment&quot;&gt;&amp;lt;!-- Post content --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post in posts.feed.entry]]&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;post-element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post]]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;selected&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[route]]&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;post-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;repeat&lt;/code&gt; attribute you see being used in our template creates and maintains an instance with [[ bindings ]] for every element in the array collection of our posts, when it is provided.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Polymer app&quot; decoding=&quot;async&quot; height=&quot;457&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/8CnsYnqdA7RiZTcTnn7W.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Now in order for us to get the current [[route]] populated, we’re going to cheat and use a library called Flatiron director which binds to [[route]] whenever the URL hash changes.&lt;/p&gt;
&lt;p&gt;Thankfully there’s a &lt;a href=&quot;https://github.com/Polymer/more-elements/tree/master/flatiron-director&quot; rel=&quot;noopener&quot;&gt;Polymer element&lt;/a&gt; (part of the &lt;a href=&quot;https://github.com/Polymer/more-elements&quot; rel=&quot;noopener&quot;&gt;more-elements&lt;/a&gt; package) that we can grab for it. Once copied to the /elements directory, we can reference it with &lt;code&gt;&amp;lt;flatiron-director route=&amp;quot;[[route]]&amp;quot; autoHash&amp;gt;&amp;lt;/flatiron-director&amp;gt;&lt;/code&gt;, specifying &lt;code&gt;route&lt;/code&gt; as the property we wish to bind to and tell it to automatically read the value of any hash changes (autoHash).&lt;/p&gt;
&lt;p&gt;Putting everything together we now get:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post.html&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;polymer-jsonp/polymer-jsonp.html&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;flatiron-director/flatiron-director.html&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;polymer-element&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;blog-element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;token attr-name&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;          &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@host&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;row&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/#&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;My Polymer Blog&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;flatiron-director&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[route]]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;autoHash&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;flatiron-director&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Posts&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Table of contents --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post in posts.feed.entry]]&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#[[post.gsx$slug.$t]]&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;[[post.gsx$title.$t]]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Post content --&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post in posts.feed.entry]]&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;post-element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post]]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;selected&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[route]]&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;post-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;polymer-jsonp&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdHVQUGd2M2Q0MEZnRms3c3dDQWQ3V1E/od6/public/values?alt=json-in-script&amp;amp;callback=&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[posts]]&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;polymer-jsonp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;Polymer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;blog-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token function-variable function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token function-variable function&quot;&gt;enteredView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token function-variable function&quot;&gt;leftView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;token function-variable function&quot;&gt;attributeChanged&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;attrName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldVal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newVal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;polymer-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Polymer App&quot; decoding=&quot;async&quot; height=&quot;635&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/MXeOmOGy9BDkzNqmmJNN.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Woo! We now have a simple blog that&#39;s reading data from JSON and using two Polymer elements scaffolded with Yeoman.&lt;/p&gt;
&lt;h3 id=&quot;working-with-3rd-party-elements&quot;&gt;Working with 3rd party elements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#working-with-3rd-party-elements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The element ecosystem around Web Components has been growing lately with component gallery sites like &lt;a href=&quot;http://customelements.io/&quot; rel=&quot;noopener&quot;&gt;customelements.io&lt;/a&gt; beginning to appear. Looking through the elements created by the community, I found one for fetching &lt;a href=&quot;https://github.com/djalmaaraujo/gravatar-element&quot; rel=&quot;noopener&quot;&gt;gravatar profiles&lt;/a&gt; and we can actually grab and add it to our blog site too.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Custom elements homepage&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/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/GVdMm7i2VwAgBR3iGfFC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Copy the gravatar element sources to your &lt;code&gt;/elements&lt;/code&gt; directory, include it via HTML imports in post.html and then add &lt;gravatar-element&gt; to your template, passing in the email field from our spreadsheet as the source of the username. Boom!&lt;/gravatar-element&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;import&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;gravatar-element/src/gravatar.html&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;polymer-element&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;post-element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post selected&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;        &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@host&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token 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;col-lg-4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post.gsx$slug.$t === selected]]&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#[[post.gsx$slug.$t]]&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;[[post.gsx$title.$t]]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;By [[post.gsx$author.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;gravatar-element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[[post.gsx$email.$t]]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;gravatar-element&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;[[post.gsx$content.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token 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;[[post.gsx$date.$t]]&lt;span class=&quot;token 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;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Keywords: [[post.gsx$keywords.$t]]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;Polymer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;post-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;enteredView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;leftView&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;attributeChanged&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;attrName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldVal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newVal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;polymer-element&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;Let’s take a look at what this gives us:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Polymer app with custom elements&quot; decoding=&quot;async&quot; height=&quot;646&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/FsMsZGDViaUkyzHwq0Na.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Beautiful!&lt;/p&gt;
&lt;p&gt;In a relatively short time, we&#39;ve created a simple application composed of several web components without having to worry about writing boilerplate code, manually downloading dependencies or setting up a local server or build workflow.&lt;/p&gt;
&lt;h3 id=&quot;optimizing-your-application&quot;&gt;Optimizing your application &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#optimizing-your-application&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Yeoman workflow includes another open-source project called &lt;a href=&quot;http://gruntjs.com/&quot;&gt;Grunt&lt;/a&gt; - a task runner that can run a number of build-specific tasks (defined in a Gruntfile) to produce an optimized version of your application. Running &lt;code&gt;grunt&lt;/code&gt; on its own will execute a &lt;code&gt;default&lt;/code&gt; task the generator has setup for linting, testing and building:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;default&#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 string&quot;&gt;&#39;jshint&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;build&#39;&lt;/span&gt;&lt;br /&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 &lt;code&gt;jshint&lt;/code&gt; task above will check with your &lt;code&gt;.jshintrc&lt;/code&gt; file to learn your preferences, then run it against all of the JavaScript files in your project. To get the full run down of your options with JSHint, check &lt;a href=&quot;http://www.jshint.com/docs/#options&quot; rel=&quot;noopener&quot;&gt;the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;test&lt;/code&gt; task looks a little like this, and can create and serve your app for the test framework we recommend out of the box, Mocha. It will also execute your tests for you:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;test&#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 string&quot;&gt;&#39;clean:server&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;createDefaultTemplate&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;jst&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;compass&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;connect:test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;mocha&#39;&lt;/span&gt;&lt;br /&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;As our app in this case is fairly simplistic, we&#39;ll leave writing tests up to you as a separate exercise. There are a few other things we&#39;ll need to have our build process handle, so let&#39;s take a look at what the &lt;code&gt;grunt build&lt;/code&gt; task defined in our &lt;code&gt;Gruntfile.js&lt;/code&gt; will do:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;build&#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 string&quot;&gt;&#39;clean:dist&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;// Clears out your .tmp/ and dist/ folders&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;compass:dist&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Compiles your Sassiness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;useminPrepare&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Looks for &amp;lt;!-- special blocks --&gt; in your HTML&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;imagemin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;// Optimizes your images!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;htmlmin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;token comment&quot;&gt;// Minifies your HTML files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// Task used to concatenate your JS and CSS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;cssmin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// Minifies your CSS files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;uglify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// Task used to minify your JS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;copy&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;// Copies files from .tmp/ and app/ into dist/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;usemin&#39;&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;// Updates the references in your HTML with the new files&lt;/span&gt;&lt;br /&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;Run &lt;code&gt;grunt build&lt;/code&gt; and a production ready version of your app should be built, ready for you to ship. Let’s try it out.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Grunt build&quot; decoding=&quot;async&quot; height=&quot;543&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/rmcqUgIwXA1fDJ71epMq.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
Success!
&lt;p&gt;If you get stuck, a pre-built version of polymer-blog is available for you to check out &lt;a href=&quot;https://github.com/addyosmani/polymer-blog&quot; rel=&quot;noopener&quot;&gt;https://github.com/addyosmani/polymer-blog&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The most common issues users run into with Yeoman, Grunt and Bower are related to not having the sufficient administrator permissions. Ensure you’ve followed the &lt;a href=&quot;https://gist.github.com/isaacs/579814&quot;&gt;recommended&lt;/a&gt; installation steps for Node and NPM. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;what-more-do-we-have-in-store&quot;&gt;What more do we have in store? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#what-more-do-we-have-in-store&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Web Components are still in a state of evolution and as such so is the tooling around them.&lt;/p&gt;
&lt;p&gt;We’re currently looking at how one might go about concatenating their HTML imports for improved loading performance via projects like &lt;a href=&quot;https://github.com/Polymer/labs/tree/master/vulcanize&quot; rel=&quot;noopener&quot;&gt;Vulcanize&lt;/a&gt; (a tool by the Polymer project) and how the ecosystem for components might work with a package manager like Bower.&lt;/p&gt;
&lt;p&gt;We’ll let you know as and when we have better answers to these questions, but there are lots of exciting times ahead.&lt;/p&gt;
&lt;h3 id=&quot;installing-polymer-standalone-with-bower&quot;&gt;Installing Polymer standalone with Bower &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#installing-polymer-standalone-with-bower&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you would prefer a lighter start to Polymer, you can install it standalone directly from Bower by running:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;bower &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; polymer&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;which will add it to your bower_components directory. You can then reference it in your application index manually and rock the future.&lt;/p&gt;
&lt;h2 id=&quot;what-do-you-think&quot;&gt;What do you think? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/yeoman/#what-do-you-think&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now you know how to scaffold out a Polymer app using Web Components with Yeoman. If you have feedback on the generator, please do let us know in the comments or file a bug or post to the Yeoman issue tracker. We would love to know if there is anything else you would like to see the generator do better as it&#39;s only through your use and feedback that we can improve :)&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author>
  </entry>
</feed>
