<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Ilya Grigorik on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Ilya Grigorik</name>
  </author>
  <link href="https://web.dev/authors/ilyagrigorik/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/ZkKPT8vEyGOWvy60ML7R.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Ilya Grigorik.</subtitle>
  
  
  <entry>
    <title>Reduce web font size</title>
    <link href="https://web.dev/reduce-webfont-size/"/>
    <updated>2019-08-16T00:00:00Z</updated>
    <id>https://web.dev/reduce-webfont-size/</id>
    <content type="html" mode="escaped">&lt;p&gt;Typography is fundamental to good design, branding, readability, and accessibility. Web fonts enable all of the above and more: the text is selectable, searchable, zoomable, and high-DPI friendly, providing consistent and sharp text rendering regardless of the screen size and resolution. WebFonts are critical to good design, UX, and performance.&lt;/p&gt;
&lt;p&gt;Web font optimization is a critical piece of the overall performance strategy. Each font is an additional resource, and some fonts may block rendering of the text, but just because the page is using WebFonts doesn&#39;t mean that it has to render slower. On the contrary, optimized fonts, combined with a judicious strategy for how they are loaded and applied on the page, can help reduce the total page size and improve page rendering times.&lt;/p&gt;
&lt;h2 id=&quot;anatomy-of-a-web-font&quot;&gt;Anatomy of a web font &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#anatomy-of-a-web-font&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;em&gt;web font&lt;/em&gt; is a collection of glyphs, and each glyph is a vector shape that describes a letter or symbol. As a result, two simple variables determine the size of a particular font file: the complexity of the vector paths of each glyph and the number of glyphs in a particular font. For example, Open Sans, which is one of the most popular WebFonts, contains 897 glyphs, which include Latin, Greek, and Cyrillic characters.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Font glyph table&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/B92rhiBJD9sx88a5CvVy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/B92rhiBJD9sx88a5CvVy.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;When picking a font, it&#39;s important to consider which character sets are supported. If you need to localize your page content to multiple languages, you should use a font that can deliver a consistent look and experience to your users. For example, &lt;a href=&quot;https://www.google.com/get/noto/&quot; rel=&quot;noopener&quot;&gt;Google&#39;s Noto font family&lt;/a&gt; aims to support all the world&#39;s languages. Note, however, that the total size of Noto, with all languages included, results in a 1.1GB+ ZIP download.&lt;/p&gt;
&lt;p&gt;In this post you will find out how to reduce the delivered filesize of your web fonts.&lt;/p&gt;
&lt;h3 id=&quot;web-font-formats&quot;&gt;Web font formats &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#web-font-formats&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today there are two recommeded font container formats in use on the web:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Embedded_OpenType&quot; rel=&quot;noopener&quot;&gt;EOT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/TrueType&quot; rel=&quot;noopener&quot;&gt;TTF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Web_Open_Font_Format&quot; rel=&quot;noopener&quot;&gt;WOFF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WOFF2/&quot; rel=&quot;noopener&quot;&gt;WOFF2&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://caniuse.com/#feat=woff&quot; rel=&quot;noopener&quot;&gt;WOFF&lt;/a&gt; and &lt;a href=&quot;http://caniuse.com/#feat=woff2&quot; rel=&quot;noopener&quot;&gt;WOFF 2.0&lt;/a&gt; enjoy wide support and are supported by all modern browsers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serve WOFF 2.0 variant to modern browsers.&lt;/li&gt;
&lt;li&gt;If absolutely necessary—such as if you still need to support Internet Explorer 11, for example—serve the WOFF as a fallback.&lt;/li&gt;
&lt;li&gt;Alternatively, consider not using web fonts for legacy browsers and falling back to the system fonts. This may be more performant for older, more constrained, devices as well.&lt;/li&gt;
&lt;li&gt;Since WOFF and WOFF 2.0 cover all bases for modern and legacy browsers still in use, use of EOT and TTF are no longer necessary and can result in longer web font download times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;web-fonts-and-compression&quot;&gt;Web fonts and compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#web-fonts-and-compression&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Both WOFF and WOFF 2.0 have built-in compression. WOFF 2.0&#39;s internal compression uses Brotli, and offers up to 30% better compression than WOFF. For more information, see &lt;a href=&quot;http://www.w3.org/TR/WOFF20ER/&quot; rel=&quot;noopener&quot;&gt;the WOFF 2.0 evaluation report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, it&#39;s worth noting that some font formats contain additional metadata, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Font_hinting&quot; rel=&quot;noopener&quot;&gt;font hinting&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Kerning&quot; rel=&quot;noopener&quot;&gt;kerning&lt;/a&gt; information that may not be necessary on some platforms, which allows for further file-size optimization. For example, &lt;a href=&quot;https://fonts.google.com/&quot; rel=&quot;noopener&quot;&gt;Google Fonts&lt;/a&gt; maintains 30+ optimized variants for each font and automatically detects and delivers the optimal variant for each platform and browser.&lt;/p&gt;
&lt;h2 id=&quot;define-a-font-family-with-font-face&quot;&gt;Define a font family with &lt;code&gt;@font-face&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#define-a-font-family-with-font-face&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;@font-face&lt;/code&gt; CSS at-rule allows you to define the location of a particular font resource, its style characteristics, and the Unicode codepoints for which it should be used. A combination of such &lt;code&gt;@font-face&lt;/code&gt; declarations can be used to construct a &amp;quot;font family,&amp;quot; which the browser will use to evaluate which font resources need to be downloaded and applied to the current page.&lt;/p&gt;
&lt;h3 id=&quot;consider-a-variable-font&quot;&gt;Consider a variable font &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#consider-a-variable-font&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Variable fonts can significantly reduce the filesize of your fonts in cases where you need multiple variants of a font. Instead of needing to load the regular and bold styles plus their italic versions, you can load a single file that contains all of the information. However, variable font file sizes will be larger than an individual font variant—though smaller than the combination of many variants. Rather than one large variable font, it may be better to serve critical font variants first, with other variants downloaded later.&lt;/p&gt;
&lt;p&gt;Variable fonts are now supported by all modern browsers, find out more in the &lt;a href=&quot;https://web.dev/variable-fonts/&quot;&gt;Introduction to variable fonts on the web&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;select-the-right-format&quot;&gt;Select the right format &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#select-the-right-format&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each &lt;code&gt;@font-face&lt;/code&gt; declaration provides the name of the font family, which acts as a logical group of multiple declarations, &lt;a href=&quot;http://www.w3.org/TR/css3-fonts/#font-prop-desc&quot; rel=&quot;noopener&quot;&gt;font properties&lt;/a&gt; such as style, weight, and stretch, and the &lt;a href=&quot;http://www.w3.org/TR/css3-fonts/#src-desc&quot; rel=&quot;noopener&quot;&gt;src descriptor&lt;/a&gt;, which specifies a prioritized list of locations for the font resource.&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;Awesome Font&#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-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;Awesome Font&#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 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;/fonts/awesome.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;/* Only serve WOFF if necessary. Otherwise,&lt;br /&gt;          WOFF 2.0 is fine by itself. */&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;/fonts/awesome.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;br /&gt;&lt;br /&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;Awesome Font&#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; italic&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;Awesome Font Italic&#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 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;/fonts/awesome-i.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 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;/fonts/awesome-i.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;First, note that the above examples define a single &lt;em&gt;Awesome Font&lt;/em&gt; family with two styles (normal and &lt;em&gt;italic&lt;/em&gt;), each of which points to a different set of font resources. In turn, each &lt;code&gt;src&lt;/code&gt; descriptor contains a prioritized, comma-separated list of resource variants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;local()&lt;/code&gt; directive allows you to reference, load, and use locally installed fonts. If the user already has the font installed on their system, this bypasses the network entirely, and is the fastest.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;url()&lt;/code&gt; directive allows you to load external fonts, and are allowed to contain an optional &lt;code&gt;format()&lt;/code&gt; hint indicating the format of the font referenced by the provided URL.&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; Unless you&#39;re referencing one of the default system fonts, it is rare for the user to have it locally installed, especially on mobile devices, where it is effectively impossible to &amp;quot;install&amp;quot; additional fonts. Even if you start with a &lt;code&gt;local()&lt;/code&gt; entry, you should always provide a list of &lt;code&gt;url()&lt;/code&gt; entries for those that do not have it downloaded. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;When the browser determines that the font is needed, it iterates through the provided resource list in the specified order and tries to load the appropriate resource. For example, following the example above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The browser performs page layout and determines which font variants are required to render the specified text on the page. Fonts that aren&#39;t part of the page&#39;s &lt;a href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/#css-object-model-cssom&quot;&gt;CSS Object Model (CSSOM)&lt;/a&gt; are not downloaded by the browser, as they are not required.&lt;/li&gt;
&lt;li&gt;For each required font, the browser checks if the font is available locally.&lt;/li&gt;
&lt;li&gt;If the font is not available locally, the browser iterates over external definitions:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;If a format hint is present, the browser checks if it supports the hint before initiating the download. If the browser doesn&#39;t support the hint, the browser advances to the next one.&lt;/li&gt;
&lt;li&gt;If no format hint is present, the browser downloads the resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The combination of local and external directives with appropriate format hints allows you to specify all of the available font formats and let the browser handle the rest. The browser determines which resources are required and selects the optimal format.&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; If you&#39;re shipping more formats than just WOFF 2.0, the order in which the font variants are specified matters. The browser picks the first format it supports. Therefore, if you want the newer browsers to use WOFF 2.0, then you should place the WOFF 2.0 declaration above WOFF. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;unicode-range-subsetting&quot;&gt;Unicode-range subsetting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#unicode-range-subsetting&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to font properties such as style, weight, and stretch, the &lt;code&gt;@font-face&lt;/code&gt; rule allows you to define a set of Unicode codepoints supported by each resource. This enables you to split a large Unicode font into smaller subsets (for example, Latin, Cyrillic, and Greek subsets) and only download the glyphs required to render the text on a particular page.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.w3.org/TR/css3-fonts/#descdef-unicode-range&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;unicode-range&lt;/code&gt; descriptor&lt;/a&gt; allows you to specify a comma-delimited list of range values, each of which can be in one of three different forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single codepoint (for example, &lt;code&gt;U+416&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Interval range (for example, &lt;code&gt;U+400-4ff&lt;/code&gt;): indicates the start and end codepoints of a range&lt;/li&gt;
&lt;li&gt;Wildcard range (for example, &lt;code&gt;U+4??&lt;/code&gt;): &lt;code&gt;?&lt;/code&gt; characters indicate any hexadecimal digit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, you can split your &lt;em&gt;Awesome Font&lt;/em&gt; family into Latin and Japanese
subsets, each of which the browser downloads on an as-needed basis:&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;Awesome Font&#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-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;Awesome Font&#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 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;/fonts/awesome-l.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;/* Latin glyphs */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+000-5FF&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@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;Awesome Font&#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-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;Awesome Font&#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 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;/fonts/awesome-jp.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;/* Japanese glyphs */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+3000-9FFF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+ff??&lt;span class=&quot;token punctuation&quot;&gt;;&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-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; Unicode-range subsetting is particularly important for Asian languages, where the number of glyphs is much larger than in Western languages and a typical &amp;quot;full&amp;quot; font is often measured in megabytes instead of tens of kilobytes. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The use of Unicode range subsets and separate files for each stylistic variant of the font allows you to define a composite font family that is both faster and more efficient to download. Visitors only download the variants and subsets they need, and they aren&#39;t forced to download subsets that they may never see or use on the page.&lt;/p&gt;
&lt;p&gt;Nearly all browsers &lt;a href=&quot;https://caniuse.com/font-unicode-range&quot; rel=&quot;noopener&quot;&gt;support &lt;code&gt;unicode-range&lt;/code&gt;&lt;/a&gt;. For compatibility with older browsers you may need to fall back to &amp;quot;manual subsetting&amp;quot;. In this case you have to fall back to providing a single font resource that contains all the necessary subsets and hide the rest from the browser. For example, if the page is only using Latin characters, then you can strip other glyphs and serve that particular subset as a standalone resource.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Determine which subsets are needed:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;If the browser supports unicode-range subsetting, then it will automatically select the right subset. The page just needs to provide the subset files and specify appropriate unicode-ranges in the &lt;code&gt;@font-face&lt;/code&gt; rules.&lt;/li&gt;
&lt;li&gt;If the browser doesn&#39;t support unicode-range subsetting, then the page needs to hide all unnecessary subsets; that is, the developer must specify the required subsets.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate font subsets:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Use the open-source &lt;a href=&quot;https://github.com/behdad/fonttools/&quot; rel=&quot;noopener&quot;&gt;pyftsubset tool&lt;/a&gt; to subset and optimize your fonts.&lt;/li&gt;
&lt;li&gt;Some font servers—such as Google Font—will automatically subset by default.&lt;/li&gt;
&lt;li&gt;Some font services allow manual subsetting via custom query parameters, which you can use to manually specify the required subset for your page. Consult the documentation from your font provider.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;font-selection-and-synthesis&quot;&gt;Font selection and synthesis &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#font-selection-and-synthesis&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each font family may be composed of multiple stylistic variants (regular, bold, italic) and multiple weights for each style. Each of which, in turn, may contain very different glyph shapes—for example, different spacing, sizing, or a different shape altogether.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Font weights&quot; decoding=&quot;async&quot; height=&quot;127&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 697px) 697px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/FNtAc2xRmx2MuUt2MADj.png?auto=format&amp;w=1394 1394w&quot; width=&quot;697&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The above diagram illustrates a font family that offers three different bold weights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;400 (regular).&lt;/li&gt;
&lt;li&gt;700 (bold).&lt;/li&gt;
&lt;li&gt;900 (extra bold).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All other in-between variants (indicated in gray) are automatically mapped to the closest variant by the browser.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;
    When a weight is specified for which no face exists, a face with a nearby weight is used. In general, bold weights map to faces with heavier weights and light weights map to faces with lighter weights.
  &lt;/p&gt;
  &lt;cite&gt;
    &lt;a href=&quot;http://www.w3.org/TR/css3-fonts/#font-matching-algorithm&quot; rel=&quot;noopener&quot;&gt;CSS font matching algorithm&lt;/a&gt;
  &lt;/cite&gt;
&lt;/blockquote&gt;
&lt;p&gt;Similar logic applies to &lt;em&gt;italic&lt;/em&gt; variants. The font designer controls which variants they will produce, and you control which variants you&#39;ll use on the page. Because each variant is a separate download, it&#39;s a good idea to keep the number of variants small. For example, you can define two bold variants for the &lt;em&gt;Awesome Font&lt;/em&gt; family:&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;Awesome Font&#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-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;Awesome Font&#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 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;/fonts/awesome-l.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;/* Latin glyphs */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+000-5FF&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@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;Awesome Font&#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-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 700&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;Awesome Font&#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 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;/fonts/awesome-l-700.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;/* Latin glyphs */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+000-5FF&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The above example declares the &lt;em&gt;Awesome Font&lt;/em&gt; family that is composed of two resources that cover the same set of Latin glyphs (&lt;code&gt;U+000-5FF&lt;/code&gt;) but offer two different &amp;quot;weights&amp;quot;: normal (400) and bold (700). However, what happens if one of your CSS rules specifies a different font weight, or sets the &lt;code&gt;font-style&lt;/code&gt; property to &lt;code&gt;italic&lt;/code&gt;?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If an exact font match isn&#39;t available, the browser substitutes the closest match.&lt;/li&gt;
&lt;li&gt;If no stylistic match is found (for example, no italic variants were declared in the example above), then the browser synthesizes its own font variant.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Font synthesis&quot; decoding=&quot;async&quot; height=&quot;356&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/a8Jo2cIO1tPsj71AzftS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-warn-bg color-state-warn-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block color-state-warn-text&quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Warning sign&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M23 21L12 2 1 21h22zm-12-3v-2h2v2h-2zm0-4h2v-4h-2v4z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Be aware that synthesized approaches may not be suitable for scripts like Cyrillic, where italic forms are very different in shape. For proper fidelity in those scripts, use an actual italic font. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The example above illustrates the difference between the actual vs. synthesized font results for Open Sans. All synthesized variants are generated from a single 400-weight font. As you can see, there&#39;s a noticeable difference in the results. The details of how to generate the bold and oblique variants are not specified. Therefore, the results vary from browser to browser, and are highly dependent on the font.&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 best consistency and visual results, don&#39;t rely on font synthesis. Instead, minimize the number of used font variants and specify their locations, such that the browser can download them when they are used on the page. Or, choose to use a variable font. That said, in some cases a synthesized variant &lt;a href=&quot;https://www.igvita.com/2014/09/16/optimizing-webfont-selection-and-synthesis/&quot;&gt;may be a viable option&lt;/a&gt;, but be cautious in using synthesized variants. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;web-font-size-optimization-checklist&quot;&gt;Web font size optimization checklist &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#web-font-size-optimization-checklist&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit and monitor your font use:&lt;/strong&gt; don&#39;t use too many fonts on your pages, and, for each font, minimize the number of used variants. This helps produce a more consistent and a faster experience for your users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid legacy formats if possible:&lt;/strong&gt; EOT, TTF, and WOFF formats are larger than WOFF 2.0. EOT and TTF are strictly unnecessary formats, where as WOFF may be acceptable if you need to support Internet Explorer 11. If you&#39;re only target modern browsers, using WOFF 2.0 only is the simplest and most performant option.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subset your font resources:&lt;/strong&gt; many fonts can be subset, or split into multiple unicode-ranges to deliver just the glyphs that a particular page requires. This reduces the file size and improves the download speed of the resource. However, when defining the subsets, be careful to optimize for font re-use. For example, don&#39;t download a different but overlapping set of characters on each page. A
good practice is to subset based on script: for example, Latin, and Cyrillic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Give precedence to &lt;code&gt;local()&lt;/code&gt; in your &lt;code&gt;src&lt;/code&gt; list:&lt;/strong&gt; listing &lt;code&gt;local(&#39;Font Name&#39;)&lt;/code&gt; first in your &lt;code&gt;src&lt;/code&gt; list ensures that HTTP requests aren&#39;t made for fonts that are already installed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;&lt;/strong&gt; to test for &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression/&quot; rel=&quot;noopener&quot;&gt;text compression&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;effects-on-largest-contentful-paint-lcp-and-cumulative-layout-shift-cls&quot;&gt;Effects on Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-webfont-size/#effects-on-largest-contentful-paint-lcp-and-cumulative-layout-shift-cls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Depending on your page&#39;s content, text nodes can be considered candidates for &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt;. It&#39;s therefore vital to ensure your web fonts are as small as possible by following the advice in this article so that your users will see the text on your page &lt;a href=&quot;https://web.dev/optimize-webfont-loading/&quot;&gt;as soon as they possibly can&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re concerned that, despite your optimization efforts, page text might take too long to appear because of large web font resource, the &lt;code&gt;font-display&lt;/code&gt; property has a number of settings that can help you to &lt;a href=&quot;https://web.dev/avoid-invisible-text&quot;&gt;avoid invisible text&lt;/a&gt; while a font is downloading. However, using the &lt;code&gt;swap&lt;/code&gt; value may cause significant layout shifts that affect your site&#39;s &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt;. Consider using the &lt;code&gt;optional&lt;/code&gt; or &lt;code&gt;fallback&lt;/code&gt; values if possible.&lt;/p&gt;
&lt;p&gt;If your web fonts are crucial to your branding—and by extension, the user experience— consider preloading your fonts so that the browser has a head start on requesting them. This can reduce both the swap period if you use &lt;code&gt;font-display: swap&lt;/code&gt;, or the blocking period if you&#39;re not using &lt;code&gt;font-display&lt;/code&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimize WebFont loading and rendering</title>
    <link href="https://web.dev/optimize-webfont-loading/"/>
    <updated>2019-08-16T00:00:00Z</updated>
    <id>https://web.dev/optimize-webfont-loading/</id>
    <content type="html" mode="escaped">&lt;p&gt;A &amp;quot;full&amp;quot; WebFont that includes all stylistic variants,
which you may not need, plus all the glyphs, which may go unused,
can easily result in a multi-megabyte download.
In this post you will find out how to optimize loading of WebFonts
so visitors only download what they will use.&lt;/p&gt;
&lt;p&gt;To address the problem of large files containing all variants,
the &lt;code&gt;@font-face&lt;/code&gt; CSS rule is specifically designed
to allow you to split the font family into a collection of resources. For example
unicode subsets, and distinct style variants.&lt;/p&gt;
&lt;p&gt;Given these declarations,
the browser figures out the required subsets and variants and downloads the minimal set required to render the text, which is very convenient.
However, if you&#39;re not careful,
it can also create a performance bottleneck in the critical rendering path and delay text rendering.&lt;/p&gt;
&lt;h3 id=&quot;the-default-behavior&quot;&gt;The default behavior &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#the-default-behavior&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lazy loading of fonts carries an important hidden implication that may delay text rendering.
The browser must &lt;a href=&quot;https://web.dev/critical-rendering-path-render-tree-construction/&quot;&gt;construct the render tree&lt;/a&gt;,
which is dependent on the DOM and CSSOM trees,
before it knows which font resources it needs to render the text.
As a result, font requests are delayed well after other critical resources,
and the browser may be blocked from rendering text until the resource is fetched.&lt;/p&gt;
&lt;img alt=&quot;Font critical rendering path&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/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/NgSTa9SirmikQAq1G5fN.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ol&gt;
&lt;li&gt;The browser requests the HTML document.&lt;/li&gt;
&lt;li&gt;The browser begins parsing the HTML response and constructing the DOM.&lt;/li&gt;
&lt;li&gt;The browser discovers CSS, JS, and other resources and dispatches requests.&lt;/li&gt;
&lt;li&gt;The browser constructs the CSSOM after all of the CSS content is received and combines it with
the DOM tree to construct the render tree.
&lt;ul&gt;
&lt;li&gt;Font requests are dispatched after the render tree indicates which font variants are needed to
render the specified text on the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The browser performs layout and paints content to the screen.
&lt;ul&gt;
&lt;li&gt;If the font is not yet available, the browser may not render any text pixels.&lt;/li&gt;
&lt;li&gt;After the font is available, the browser paints the text pixels.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &amp;quot;race&amp;quot; between the first paint of page content,
which can be done shortly after the render tree is built,
and the request for the font resource is what creates the &amp;quot;blank text problem&amp;quot;
where the browser might render page layout but omits any text.&lt;/p&gt;
&lt;p&gt;By preloading WebFonts and using &lt;code&gt;font-display&lt;/code&gt; to control how browsers behave with unavailable fonts,
you can prevent blank pages and layout shifts due to font loading.&lt;/p&gt;
&lt;h3 id=&quot;preload-your-webfont-resources&quot;&gt;Preload your WebFont resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#preload-your-webfont-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If there&#39;s a high probability that your page will need a specific WebFont hosted at a URL you know in advance,
you can take advantage of &lt;a href=&quot;https://web.dev/prioritize-resources/&quot;&gt;resource prioritization&lt;/a&gt;.
Using &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; will trigger a request for the WebFont early in the critical rendering path,
without having to wait for the CSSOM to be created.&lt;/p&gt;
&lt;h3 id=&quot;customize-the-text-rendering-delay&quot;&gt;Customize the text rendering delay &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#customize-the-text-rendering-delay&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While preloading makes it more likely that a WebFont will be available when a page&#39;s content is rendered,
it offers no guarantees.
You still need to consider how browsers behave when rendering text that uses a &lt;code&gt;font-family&lt;/code&gt; which is not yet available.&lt;/p&gt;
&lt;p&gt;In the post &lt;a href=&quot;https://web.dev/avoid-invisible-text/&quot;&gt;Avoid invisible text during font loading&lt;/a&gt; you can see that default browser behavior is not consistent.
However, you can tell modern browsers how you want them to behave by using
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;font-display&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 60, 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;
      60
    &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 58, 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;
      58
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 11.1, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      11.1
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Similar to the existing font timeout behaviors that some browsers implement,
&lt;code&gt;font-display&lt;/code&gt; segments the lifetime of a font download into three major periods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first period is the &lt;strong&gt;font block period&lt;/strong&gt;.
During this period, if the font face is not loaded,
any element attempting to use it must instead render with an invisible fallback font face.
If the font face successfully loads during the block period, the font face is then used normally.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;font swap period&lt;/strong&gt; occurs immediately after the font block period.
During this period, if the font face is not loaded,
any element attempting to use it must instead render with a fallback font face.
If the font face successfully loads during the swap period, the font face is then used normally.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;font failure period&lt;/strong&gt; occurs immediately after the font swap period.
If the font face is not yet loaded when this period starts,
it&#39;s marked as a failed load, causing normal font fallback.
Otherwise, the font face is used normally.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Understanding these periods means you can use &lt;code&gt;font-display&lt;/code&gt; to decide how your
font should render depending on whether or when it was downloaded.&lt;/p&gt;
&lt;p&gt;To work with the &lt;code&gt;font-display&lt;/code&gt; property, add it to your &lt;code&gt;@font-face&lt;/code&gt; rules:&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;Awesome Font&#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-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;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* or block, swap, fallback, optional */&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;Awesome Font&#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 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;/fonts/awesome-l.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;span class=&quot;token comment&quot;&gt;/* will be preloaded */&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;/fonts/awesome-l.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 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;/fonts/awesome-l.ttf&#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;truetype&#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 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;/fonts/awesome-l.eot&#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;embedded-opentype&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+000-5FF&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Latin glyphs */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;font-display&lt;/code&gt; currently supports the following range of values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;block&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;swap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fallback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;optional&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more information on preloading fonts, and the &lt;code&gt;font-display&lt;/code&gt; property, see the following posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/avoid-invisible-text/&quot;&gt;Avoid invisible text during font loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/font-display/&quot; rel=&quot;noopener&quot;&gt;Controlling font performance using font-display&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/preload-optional-fonts/&quot;&gt;Prevent layout shifting and flashes of invisibile text (FOIT) by preloading optional fonts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-font-loading-api&quot;&gt;The Font Loading API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#the-font-loading-api&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Used together, &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; and the CSS &lt;code&gt;font-display&lt;/code&gt; give you a great deal of control over font loading and rendering,
without adding in much overhead.
But if you need additional customizations,
and are willing to incur the overhead introduced by running JavaScript, there is another option.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.w3.org/TR/css-font-loading/&quot; rel=&quot;noopener&quot;&gt;Font Loading API&lt;/a&gt; provides a scripting interface to define and manipulate CSS font faces,
track their download progress, and override their default lazyload behavior.
For example, if you&#39;re sure that a particular font variant is required,
you can define it and tell the browser to initiate an immediate fetch of the font resource:&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 35, 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;
      35
    &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 41, 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;
      41
    &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 10, 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;
      10
    &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/API/FontFace#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&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 keyword&quot;&gt;var&lt;/span&gt; font &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;FontFace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Awesome Font&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;url(/fonts/awesome.woff2)&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 literal-property property&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;normal&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;unicodeRange&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;U+000-5FF&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;400&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// don&#39;t wait for the render tree, initiate an immediate fetch!&lt;/span&gt;&lt;br /&gt;font&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&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 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;// apply the font (which may re-render text and cause a page reflow)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// after the font has finished downloading&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;font&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fontFamily &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Awesome Font, serif&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// OR... by default the content is hidden,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// and it&#39;s rendered after the font is available&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;content&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;  content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;visibility &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;visible&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// OR... apply your own render strategy here...&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;Further, because you can check the font status
(via the &lt;a href=&quot;https://www.w3.org/TR/css-font-loading/#font-face-set-check&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;check()&lt;/code&gt;&lt;/a&gt;) method
and track its download progress,
you can also define a custom strategy for rendering text on your pages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can hold all text rendering until the font is available.&lt;/li&gt;
&lt;li&gt;You can implement a custom timeout for each font.&lt;/li&gt;
&lt;li&gt;You can use the fallback font to unblock rendering and inject a new style that uses the desired
font after the font is available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best of all, you can also mix and match the above strategies for different content on the page.
For example, you can delay text rendering on some sections until the font is available,
use a fallback font, and then re-render after the font download has finished.&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 Font Loading API is &lt;a href=&quot;http://caniuse.com/#feat=font-loading&quot;&gt;not available in older browsers&lt;/a&gt;. Consider using the &lt;a href=&quot;https://github.com/bramstein/fontloader&quot;&gt;FontLoader polyfill&lt;/a&gt; or the &lt;a href=&quot;https://github.com/typekit/webfontloader&quot;&gt;WebFontloader library&lt;/a&gt; to deliver similar functionality, albeit with even more overhead from an additional JavaScript dependency. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;proper-caching-is-a-must&quot;&gt;Proper caching is a must &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#proper-caching-is-a-must&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Font resources are, typically, static resources that don&#39;t see frequent updates.
As a result, they are ideally suited for a long max-age expiry—
ensure that you specify both a &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;conditional ETag header&lt;/a&gt;,
and an &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;optimal Cache-Control policy&lt;/a&gt; for all font resources.&lt;/p&gt;
&lt;p&gt;If your web application uses a &lt;a href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview/&quot; rel=&quot;noopener&quot;&gt;service worker&lt;/a&gt;,
serving font resources with a &lt;a href=&quot;https://web.dev/offline-cookbook/#cache-then-network&quot;&gt;cache-first strategy&lt;/a&gt; is appropriate for most use cases.&lt;/p&gt;
&lt;p&gt;You should not store fonts using &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/localStorage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/a&gt;
or &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/IndexedDB_API&quot; rel=&quot;noopener&quot;&gt;IndexedDB&lt;/a&gt;;
each of those has its own set of performance issues.
The browser&#39;s HTTP cache provides the best and most robust mechanism to deliver font resources to the browser.&lt;/p&gt;
&lt;h2 id=&quot;webfont-loading-checklist&quot;&gt;WebFont loading checklist &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#webfont-loading-checklist&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customize font loading and rendering using &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt;, &lt;code&gt;font-display&lt;/code&gt;, or the Font
Loading API:&lt;/strong&gt; default lazyloading behavior may result in delayed text rendering. These web platform
features allow you to override this behavior for particular fonts, and to specify custom rendering
and timeout strategies for different content on the page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specify revalidation and optimal caching policies:&lt;/strong&gt; fonts are static resources that are
infrequently updated. Make sure that your servers provide a long-lived max-age timestamp and a
revalidation token to allow for efficient font reuse between different pages. If using a service
worker, a cache-first strategy is appropriate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;automated-testing-for-webfont-loading-behavior-with-lighthouse&quot;&gt;Automated testing for WebFont loading behavior with Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-webfont-loading/#automated-testing-for-webfont-loading-behavior-with-lighthouse&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;
can help automate the process of making sure that you&#39;re following web font optimization best practices.&lt;/p&gt;
&lt;p&gt;The following audits can help you make sure that your pages are continuing to follow web font optimization best practices over time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preload/&quot; rel=&quot;noopener&quot;&gt;Preload key requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-long-cache-ttl/&quot; rel=&quot;noopener&quot;&gt;Uses inefficient cache policy on static assets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/font-display/&quot; rel=&quot;noopener&quot;&gt;All text remains visible during WebFont loads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Prevent unnecessary network requests with the HTTP Cache</title>
    <link href="https://web.dev/http-cache/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/http-cache/</id>
    <content type="html" mode="escaped">&lt;p&gt;Fetching resources over the network is both slow and expensive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large responses require many roundtrips between the browser and the server.&lt;/li&gt;
&lt;li&gt;Your page won&#39;t load until all of its &lt;a href=&quot;https://web.dev/critical-rendering-path/&quot;&gt;critical resources&lt;/a&gt; have downloaded completely.&lt;/li&gt;
&lt;li&gt;If a person is accessing your site with a limited mobile data plan, every unnecessary
network request is a waste of their money.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can you avoid unnecessary network requests? The browser&#39;s HTTP Cache is your
first line of defense. It&#39;s not necessarily the most powerful or flexible
approach, and you have limited control over the lifetime of cached responses,
but it&#39;s effective, it&#39;s supported in all browsers, and it doesn&#39;t require much
work.&lt;/p&gt;
&lt;p&gt;This guide shows you the basics of an effective HTTP caching implementation.&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/http-cache/#browser-compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There isn&#39;t actually a single API called the HTTP Cache. It&#39;s the general name
for a collection of web platform APIs. Those APIs are supported in all browsers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control#Browser_compatibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Cache-Control&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag#Browser_compatibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Last-Modified#Browser_compatibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;overview&quot;&gt;How the HTTP Cache works &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All HTTP requests that the browser makes are first routed to the browser cache
to check whether there is a valid cached response that can be used to fulfill
the request. If there&#39;s a match, the response is read from the cache, which
eliminates both the network latency and the data costs that the transfer incurs.&lt;/p&gt;
&lt;p&gt;The HTTP Cache&#39;s behavior is controlled by a combination of
&lt;a href=&quot;https://developer.mozilla.org/docs/Glossary/Request_header&quot; rel=&quot;noopener&quot;&gt;request headers&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/docs/Glossary/Response_header&quot; rel=&quot;noopener&quot;&gt;response headers&lt;/a&gt;.
In an ideal scenario, you&#39;ll have control over both the code for your
web application (which will determine the request headers) and your web server&#39;s
configuration (which will determine the response headers).&lt;/p&gt;
&lt;p&gt;Check out MDN&#39;s &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Caching&quot; rel=&quot;noopener&quot;&gt;HTTP Caching&lt;/a&gt; article
for a more in-depth conceptual overview.&lt;/p&gt;
&lt;h2 id=&quot;request-headers&quot;&gt;Request headers: stick with the defaults (usually) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#request-headers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While there are a number of important headers that should be included in your
web app&#39;s outgoing requests, the browser almost always takes care of setting
them on your behalf when it makes requests. Request headers that affect checking
for freshness, like &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/If-None-Match&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;If-None-Match&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/If-Modified-Since&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;If-Modified-Since&lt;/code&gt;&lt;/a&gt; just appear based on the browser&#39;s
understanding of the current values in the HTTP Cache.&lt;/p&gt;
&lt;p&gt;This is good news—it means that you can continue including tags like &lt;code&gt;&amp;lt;img src=&amp;quot;my-image.png&amp;quot;&amp;gt;&lt;/code&gt; in your HTML, and the browser  automatically takes care of
HTTP caching for you, without extra effort.&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; Developers who do need more control over the HTTP Cache in their web application have an alternative—you can &amp;quot;drop down&amp;quot; a level, and manually use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Fetch_API&quot;&gt;Fetch API&lt;/a&gt;, passing it &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Request&quot;&gt;&lt;code&gt;Request&lt;/code&gt;&lt;/a&gt; objects with specific &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Request/cache&quot;&gt;&lt;code&gt;cache&lt;/code&gt;&lt;/a&gt; overrides set. That&#39;s beyond the scope of this guide, though! &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;response-headers&quot;&gt;Response headers: configure your web server &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#response-headers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The part of the HTTP caching setup that matters the most is the headers that
your web server adds to each outgoing response. The following headers all factor
into effective caching behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Cache-Control&lt;/code&gt;&lt;/a&gt;.
The server can return a &lt;code&gt;Cache-Control&lt;/code&gt; directive to specify how, and for how
long, the browser and other intermediate caches should cache the individual
response.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/a&gt;. When
the browser finds an expired cached response, it can send a small token
(usually a hash of the file&#39;s contents) to the server to check if the file has
changed. If the server returns the same token, then the file is the same, and there&#39;s
no need to re-download it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Last-Modified&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/a&gt;.
This header serves the same purpose as &lt;code&gt;ETag&lt;/code&gt;, but uses a time-based strategy
to determine if a resource has changed, as opposed to the content-based strategy
of &lt;code&gt;ETag&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some web servers have built-in support for setting those headers by default,
while others leave the headers out entirely unless you explicitly configure
them. The specific details of &lt;em&gt;how&lt;/em&gt; to configure headers varies greatly
depending on which web server you use, and you should consult your server&#39;s
documentation to get the most accurate details.&lt;/p&gt;
&lt;p&gt;To save you some searching, here are instructions on configuring a few popular
web servers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://expressjs.com/en/api.html#express.static&quot; rel=&quot;noopener&quot;&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/2.4/caching.html&quot; rel=&quot;noopener&quot;&gt;Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nginx.org/en/docs/http/ngx_http_headers_module.html&quot; rel=&quot;noopener&quot;&gt;nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firebase.google.com/docs/hosting/full-config&quot; rel=&quot;noopener&quot;&gt;Firebase Hosting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/blog/2017/02/23/better-living-through-caching/&quot; rel=&quot;noopener&quot;&gt;Netlify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Leaving out the &lt;code&gt;Cache-Control&lt;/code&gt; response header does not disable HTTP caching!
Instead, browsers &lt;a href=&quot;https://www.mnot.net/blog/2017/03/16/browser-caching#heuristic-freshness&quot; rel=&quot;noopener&quot;&gt;effectively
guess&lt;/a&gt;
what type of caching behavior makes the most sense for a given type of content.
Chances are you want more control than that offers, so take the time to
configure your response headers.&lt;/p&gt;
&lt;h2 id=&quot;response-header-strategies&quot;&gt;Which response header values should you use? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#response-header-strategies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two important scenarios that you should cover when configuring your
web server&#39;s response headers.&lt;/p&gt;
&lt;h3 id=&quot;versioned-urls&quot;&gt;Long-lived caching for versioned URLs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#versioned-urls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;details&gt;
  &lt;summary&gt;
  How versioned URLs can help your caching strategy
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt;    Versioned URLs are a good practice because they make it easier to invalidate cached responses.&lt;/p&gt;
&lt;/summary&gt;
  Suppose your server instructs browsers to cache a CSS file
  for 1 year (&lt;code&gt;Cache-Control: max-age=31536000&lt;/code&gt;) but your designer just made an
  emergency update that you need to roll out immediately. How do you notify browsers
  to update the &quot;stale&quot; cached copy of the file?
  You can&#39;t, at least not without changing the URL of the resource. After the
  browser caches the response, the cached version is used until it&#39;s no longer
  fresh, as determined by &lt;code&gt;max-age&lt;/code&gt; or &lt;code&gt;expires&lt;/code&gt;, or until it is evicted from the cache
  for some other reason—for example, the user clearing their browser cache. As a
  result, different users might end up using different versions of the file when
  the page is constructed: users who just fetched the resource use the new
  version, while users who cached an earlier (but still valid) copy use an older
  version of its response. How do you get the best of both worlds: client-side
  caching and quick updates? You change the URL of the resource and force the user
  to download the new response whenever its content changes. Typically, you do
  this by embedding a fingerprint of the file, or a version number, in its
  filename—for example, &lt;code&gt;style.x234dff.css&lt;/code&gt;.
&lt;/details&gt;
&lt;p&gt;When responding to requests for URLs that contain
&amp;quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Fingerprint_(computing)&quot; rel=&quot;noopener&quot;&gt;fingerprint&lt;/a&gt;&amp;quot; or
versioning information, and whose contents are never meant to change, add
&lt;code&gt;Cache-Control: max-age=31536000&lt;/code&gt; to your responses.&lt;/p&gt;
&lt;p&gt;Setting this value tells the browser that when it needs to load the same URL
anytime over the next one year (31,536,000 seconds; the maximum supported
value), it can immediately use the value in the HTTP Cache, without having
to make a network request to your web server at all. That&#39;s great—you&#39;ve
immediately gained the reliability and speed that comes from avoiding the
network!&lt;/p&gt;
&lt;p&gt;Build tools like webpack can
&lt;a href=&quot;https://webpack.js.org/guides/caching/#output-filenames&quot; rel=&quot;noopener&quot;&gt;automate the process&lt;/a&gt;
of assigning hash fingerprints to your asset URLs.&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 also add the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control#Revalidation_and_reloading&quot;&gt;&lt;code&gt;immutable&lt;/code&gt; property&lt;/a&gt; to your &lt;code&gt;Cache-Control&lt;/code&gt; header as a further optimization, though it &lt;a href=&quot;https://www.keycdn.com/blog/cache-control-immutable#browser-support&quot;&gt;will be ignored&lt;/a&gt; in some browsers. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;unversioned-urls&quot;&gt;Server revalidation for unversioned URLs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#unversioned-urls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, not all of the URLs you load are versioned. Maybe you&#39;re not able
to include a build step prior to deploying your web app, so you can&#39;t add hashes
to your asset URLs. And every web application needs HTML files—those files are
(almost!) never going to include versioning information, since no one will
bother to use your web app if they need to remember that the URL to visit is
&lt;code&gt;https://example.com/index.34def12.html&lt;/code&gt;. So what can you do for those URLs?&lt;/p&gt;
&lt;p&gt;This is one scenario in which you need to admit defeat. HTTP caching alone isn&#39;t
powerful enough to avoid the network completely. (Don&#39;t worry—you&#39;ll soon learn
about &lt;a href=&quot;https://web.dev/service-workers-cache-storage/&quot;&gt;service workers&lt;/a&gt;, which will provide the
support we need to swing the battle back in your favor.) But there are a few
steps you can take to make sure that network requests are as quick and efficient
as possible.&lt;/p&gt;
&lt;p&gt;The following &lt;code&gt;Cache-Control&lt;/code&gt; values can help you fine-tune where and how unversioned URLs
are cached:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;no-cache&lt;/code&gt;. This instructs the browser that it must revalidate with the
server every time before using a cached version of the URL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;no-store&lt;/code&gt;. This instructs the browser and other intermediate caches (like CDNs) to never
store any version of the file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt;. Browsers can cache the file but intermediate caches cannot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt;. The response can be stored by any cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://web.dev/http-cache/#flowchart&quot;&gt;Appendix: &lt;code&gt;Cache-Control&lt;/code&gt; flowchart&lt;/a&gt; to visualize the process
of deciding which &lt;code&gt;Cache-Control&lt;/code&gt; value(s) to use. Note also that &lt;code&gt;Cache-Control&lt;/code&gt; can
accept a comma-separated list of directives. See &lt;a href=&quot;https://web.dev/http-cache/#examples&quot;&gt;Appendix: &lt;code&gt;Cache-Control&lt;/code&gt; examples&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Along with that, setting one of two additional response headers can also help:
either &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Last-Modified&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/a&gt;. As mentioned in
&lt;a href=&quot;https://web.dev/http-cache/#response-headers&quot;&gt;Response headers&lt;/a&gt;, &lt;code&gt;ETag&lt;/code&gt; and &lt;code&gt;Last-Modified&lt;/code&gt; both serve the
same purpose: determining if the browser needs to re-download a cached file
that has expired. &lt;code&gt;ETag&lt;/code&gt; is the recommended approach because it&#39;s more accurate.&lt;/p&gt;
&lt;details&gt;
  &lt;summary&gt;
  ETag example
&lt;/summary&gt;
  Assume that 120 seconds have passed since the initial fetch and the browser
  has initiated a new request for the same resource. First, the browser checks
  the HTTP Cache and finds the previous response. Unfortunately, the browser
  can&#39;t use the previous response because the response has now expired. At this
  point, the browser could dispatch a new request and fetch the new full
  response. However, that&#39;s inefficient because if the resource hasn&#39;t changed,
  then there&#39;s no reason to download the same information that&#39;s already in the
  cache! That&#39;s the problem that validation tokens, as specified in the &lt;code&gt;ETag&lt;/code&gt;
  header, are designed to solve. The server generates and returns an arbitrary
  token, which is typically a hash or some other fingerprint of the contents of
  the file. The browser doesn&#39;t need to know how the fingerprint is generated; it
  only needs to send it to the server on the next request. If the fingerprint is
  still the same, then the resource hasn&#39;t changed and the browser can skip the
  download.
&lt;/details&gt;
&lt;p&gt;By setting &lt;code&gt;ETag&lt;/code&gt; or &lt;code&gt;Last-Modified&lt;/code&gt;, you&#39;ll end up making the
revalidation request much more efficient. They end up triggering the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/If-Modified-Since&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;If-Modified-Since&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/If-None-Match&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;If-None-Match&lt;/code&gt;&lt;/a&gt;
request headers that were mentioned in &lt;a href=&quot;https://web.dev/http-cache/#request-headers&quot;&gt;Request headers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When a properly configured web server sees those incoming request headers, it
can confirm whether the version of the resource that the browser already has in
its HTTP Cache matches the latest version on the web server. If there&#39;s a match,
then the server can respond with a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Status/304&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;304 Not Modified&lt;/code&gt;&lt;/a&gt; HTTP response,
which is the equivalent of &amp;quot;Hey, keep using what you&#39;ve already got!&amp;quot; There&#39;s
very little data to transfer when sending this type of response, so it&#39;s usually
much faster than having to actually send back a copy of the actual resource
being requested.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A diagram of a client requesting a resource and the server responding with a 304 header.&quot; decoding=&quot;async&quot; height=&quot;215&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 474px) 474px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/e2bN6glWoVbWIcwUF1uh.png?auto=format&amp;w=948 948w&quot; width=&quot;474&quot; /&gt;
  &lt;figcaption&gt;
    The browser requests &lt;code&gt;/file&lt;/code&gt; from the server and includes the &lt;code&gt;If-None-Match&lt;/code&gt;
    header to instruct the server to only return the full file if the &lt;code&gt;ETag&lt;/code&gt; of
    the file on the server doesn&#39;t match the browser&#39;s &lt;code&gt;If-None-Match&lt;/code&gt; value. In this
    case, the 2 values did match, so the server returns a &lt;code&gt;304 Not Modified&lt;/code&gt; response
    with instructions on how much longer the file should be cached (&lt;code&gt;Cache-Control: max-age=120&lt;/code&gt;).
  &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/http-cache/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The HTTP Cache is an effective way to improve load performance because
it reduces unnecessary network requests. It&#39;s supported in all browsers and doesn&#39;t
take too much work to set up.&lt;/p&gt;
&lt;p&gt;The following &lt;code&gt;Cache-Control&lt;/code&gt; configurations are a good start:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Cache-Control: no-cache&lt;/code&gt; for resources that should be revalidated with the server before every use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cache-Control: no-store&lt;/code&gt; for resources that should never be cached.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cache-Control: max-age=31536000&lt;/code&gt; for versioned resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the &lt;code&gt;ETag&lt;/code&gt; or &lt;code&gt;Last-Modified&lt;/code&gt; header can help you revalidate expired cache resources more efficiently.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Try the &lt;a href=&quot;https://web.dev/codelab-http-cache&quot;&gt;HTTP Cache codelab&lt;/a&gt; to get hands-on experience with &lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt; in Express. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;learn-more&quot;&gt;Learn more &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#learn-more&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re looking to go beyond the basics of using the &lt;code&gt;Cache-Control&lt;/code&gt; header,
check out Jake Archibald&#39;s &lt;a href=&quot;https://jakearchibald.com/2016/caching-best-practices/&quot; rel=&quot;noopener&quot;&gt;Caching best practices &amp;amp; max-age
gotchas&lt;/a&gt; guide.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://web.dev/love-your-cache&quot;&gt;Love your cache&lt;/a&gt; for guidance on how to optimize
your cache usage for return visitors.&lt;/p&gt;
&lt;h2 id=&quot;tips&quot;&gt;Appendix: More tips &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#tips&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have more time, here are further ways that you can optimize your usage of the HTTP Cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use consistent URLs. If you serve the same content on different URLs, then
that content will be fetched and stored multiple times.&lt;/li&gt;
&lt;li&gt;Minimize churn. If part of a resource (such as a CSS file) updates frequently, whereas the
rest of the file does not (such as library code), consider splitting the frequently updating
code into a separate file and using a short duration caching strategy for the frequently
updating code and a long caching duration strategy for the code that doesn&#39;t change often.&lt;/li&gt;
&lt;li&gt;Check out the new &lt;a href=&quot;https://web.dev/stale-while-revalidate/&quot;&gt;&lt;code&gt;stale-while-revalidate&lt;/code&gt;&lt;/a&gt; directive if
some degree of staleness is acceptable in your &lt;code&gt;Cache-Control&lt;/code&gt; policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flowchart&quot;&gt;Appendix: &lt;code&gt;Cache-Control&lt;/code&gt; flowchart &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#flowchart&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;img alt=&quot;Flowchart&quot; decoding=&quot;async&quot; height=&quot;600&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 595px) 595px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/htXr84PI8YR0lhgLPiqZ.png?auto=format&amp;w=1190 1190w&quot; width=&quot;595&quot; /&gt;
&lt;h2 id=&quot;examples&quot;&gt;Appendix: &lt;code&gt;Cache-Control&lt;/code&gt; examples &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/http-cache/#examples&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;&lt;code&gt;Cache-Control&lt;/code&gt; value&lt;/th&gt;
        &lt;th&gt;Explanation&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;max-age=86400&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;
          The response can be cached by browsers and intermediary caches for
          up to 1 day (60 seconds x 60 minutes x 24 hours).
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;private, max-age=600&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;
          The response can be cached by the browser (but not intermediary caches) for up to 10
          minutes (60 seconds x 10 minutes).
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;public, max-age=31536000&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;
          The response can be stored by any cache for 1 year.
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;code&gt;no-store&lt;/code&gt;&lt;/td&gt;
        &lt;td&gt;
          The response is not allowed to be cached and must be fetched in full on every request.
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
</content>
    <author>
      <name>Jeff Posnick</name>
    </author><author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Choose the right image format</title>
    <link href="https://web.dev/choose-the-right-image-format/"/>
    <updated>2018-08-30T00:00:00Z</updated>
    <id>https://web.dev/choose-the-right-image-format/</id>
    <content type="html" mode="escaped">&lt;p&gt;The very first question you should ask yourself is whether an image is,
in fact, required to achieve the effect you are after.
Good design is simple and will also always yield the best performance.
If you can eliminate an image resource,
which often requires a large number of bytes relative to HTML, CSS, JavaScript and other assets on the page,
then that is always the best optimization strategy.
That said, a well-placed image can also communicate more information than a thousand words,
so it is up to you to find that balance.&lt;/p&gt;
&lt;p&gt;Next, you should consider if there is an alternative technology that could deliver the desired results,
but in a more efficient manner:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CSS effects&lt;/strong&gt; (such as shadows or gradients) and CSS animations
can be used to produce resolution-independent assets that always look sharp at every resolution and zoom level,
often at a fraction of the bytes required by an image file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web fonts&lt;/strong&gt; enable use of beautiful typefaces
while preserving the ability to select, search,
and resize text—a significant improvement in usability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you ever find yourself encoding text in an image asset, stop and reconsider.
Great typography is critical to good design, branding, and readability,
but text-in-images delivers a poor user experience:
the text is not selectable, not searchable, not zoomable,
not accessible, and not friendly for high-DPI devices.
The use of web fonts requires its &lt;a href=&quot;https://www.igvita.com/2014/01/31/optimizing-web-font-rendering-performance/&quot; rel=&quot;noopener&quot;&gt;own set of optimizations&lt;/a&gt;,
but it addresses all of these concerns and is always a better choice for displaying text.&lt;/p&gt;
&lt;h2 id=&quot;choose-the-right-image-format&quot;&gt;Choose the right image format &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/choose-the-right-image-format/#choose-the-right-image-format&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are sure an image is the correct option, you should carefully select the right kind of image for the job.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Zoomed-in vector and raster images&quot; decoding=&quot;async&quot; height=&quot;313&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 585px) 585px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/dJuB2DQcbhtwD5VdPVlR.png?auto=format&amp;w=1170 1170w&quot; width=&quot;585&quot; /&gt;
  &lt;figcaption&gt;Zoomed-in vector image (L) raster image (R)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Vector_graphics&quot; rel=&quot;noopener&quot;&gt;Vector graphics&lt;/a&gt;
use lines, points, and polygons to represent an image.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Raster_graphics&quot; rel=&quot;noopener&quot;&gt;Raster graphics&lt;/a&gt;
represent an image by encoding the individual values of each pixel within a rectangular grid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each format has its own set of pros and cons.
Vector formats are ideally suited for images that consist of simple geometric shapes such as logos, text, or icons.
They deliver sharp results at every resolution and zoom setting,
which makes them an ideal format for high-resolution screens and assets that need to be displayed at varying sizes.&lt;/p&gt;
&lt;p&gt;However, vector formats fall short when the scene is complicated (for example, a photo):
the amount of SVG markup to describe all the shapes can be prohibitively high
and the output may still not look &amp;quot;photorealistic&amp;quot;.
When that&#39;s the case, that&#39;s when you should be using a raster image format
such as PNG, JPEG, WebP, or AVIF.&lt;/p&gt;
&lt;p&gt;Raster images do not have the same nice properties of being resolution or zoom independent
—when you scale up a raster image you&#39;ll see jagged and blurry graphics.
As a result, you may need to save multiple versions of a raster image at various resolutions
to deliver the optimal experience to your users.&lt;/p&gt;
&lt;h2 id=&quot;implications-of-high-resolution-screens&quot;&gt;Implications of high-resolution screens &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/choose-the-right-image-format/#implications-of-high-resolution-screens&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two different kinds of pixels: CSS pixels and device pixels.
A single CSS pixel may correspond directly to a single device pixel, or may be backed by multiple device pixels.
What&#39;s the point? Well, the more device pixels there are, the finer the detail of the displayed content on the screen.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Three images showing the difference between CSS pixels and device pixels.&quot; decoding=&quot;async&quot; height=&quot;205&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 470px) 470px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/oQV7qJ9fUMkYsKlUMrL4.png?auto=format&amp;w=940 940w&quot; width=&quot;470&quot; /&gt;
  &lt;figcaption&gt;The difference between CSS pixels and device pixels.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;High DPI (HiDPI) screens produce beautiful results, but there is one obvious tradeoff:
image assets require more detail to take advantage of the higher device pixel counts.
The good news is, vector images are ideally suited for this task,
as they can be rendered at any resolution with sharp results—
you might incur a higher processing cost to render the finer detail,
but the underlying asset is the same and is resolution independent.&lt;/p&gt;
&lt;p&gt;On the other hand, raster images pose a much larger challenge because they encode image data on a per-pixel basis.
Hence, the larger the number of pixels, the larger the filesize of a raster image.
As an example, let&#39;s consider the difference between a photo asset displayed at 100x100 (CSS) pixels:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
&lt;table&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Screen resolution&lt;/th&gt;
    &lt;th&gt;Total pixels&lt;/th&gt;
    &lt;th&gt;Uncompressed filesize (4 bytes per pixel)&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;resolution&quot;&gt;1x&lt;/td&gt;
  &lt;td data-th=&quot;total pixels&quot;&gt;100 x 100 = 10,000&lt;/td&gt;
  &lt;td data-th=&quot;filesize&quot;&gt;40,000 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;resolution&quot;&gt;2x&lt;/td&gt;
  &lt;td data-th=&quot;total pixels&quot;&gt;100 x 100 x 4 = 40,000&lt;/td&gt;
  &lt;td data-th=&quot;filesize&quot;&gt;160,000 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;resolution&quot;&gt;3x&lt;/td&gt;
  &lt;td data-th=&quot;total pixels&quot;&gt;100 x 100 x 9 = 90,000&lt;/td&gt;
  &lt;td data-th=&quot;filesize&quot;&gt;360,000 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;When we double the resolution of the physical screen,
the total number of pixels increases by a factor of four:
double the number of horizontal pixels, times double the number of vertical pixels.
Hence, a &amp;quot;2x&amp;quot; screen not just doubles, but quadruples the number of required pixels!&lt;/p&gt;
&lt;p&gt;So, what does this mean in practice?
High-resolution screens enable you to deliver beautiful images, which can be a great product feature.
However, high-resolution screens also require high-resolution images, therefore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prefer vector images whenever possible as they are resolution-independent and always deliver sharp results.&lt;/li&gt;
&lt;li&gt;If a raster image is required, serve &lt;a href=&quot;https://web.dev/serve-responsive-images/&quot;&gt;responsive images&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;features-of-different-raster-image-formats&quot;&gt;Features of different raster image formats &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/choose-the-right-image-format/#features-of-different-raster-image-formats&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to different lossy and lossless compression algorithms,
different image formats support different features such as animation and transparency (alpha) channels.
As a result, the choice of the &amp;quot;right format&amp;quot; for a particular image is a combination of desired visual results and functional requirements.&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
&lt;table&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Format&lt;/th&gt;
    &lt;th&gt;Transparency&lt;/th&gt;
    &lt;th&gt;Animation&lt;/th&gt;
    &lt;th&gt;Browser&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;format&quot;&gt;&lt;a rel=&quot;noopener&quot; href=&quot;http://en.wikipedia.org/wiki/Portable_Network_Graphics&quot;&gt;PNG&lt;/a&gt;&lt;/td&gt;
  &lt;td data-th=&quot;transparency&quot;&gt;Yes&lt;/td&gt;
  &lt;td data-th=&quot;animation&quot;&gt;No&lt;/td&gt;
  &lt;td data-th=&quot;browser&quot;&gt;All&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;format&quot;&gt;&lt;a rel=&quot;noopener&quot; href=&quot;http://en.wikipedia.org/wiki/JPEG&quot;&gt;JPEG&lt;/a&gt;&lt;/td&gt;
  &lt;td data-th=&quot;transparency&quot;&gt;No&lt;/td&gt;
  &lt;td data-th=&quot;animation&quot;&gt;No&lt;/td&gt;
  &lt;td data-th=&quot;browser&quot;&gt;All&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;format&quot;&gt;&lt;a rel=&quot;noopener&quot; href=&quot;http://en.wikipedia.org/wiki/WebP&quot;&gt;WebP&lt;/a&gt;&lt;/td&gt;
  &lt;td data-th=&quot;transparency&quot;&gt;Yes&lt;/td&gt;
  &lt;td data-th=&quot;animation&quot;&gt;Yes&lt;/td&gt;
  &lt;td data-th=&quot;browser&quot;&gt;All modern browsers. See &lt;a href=&quot;https://caniuse.com/#feat=webp&quot;&gt;Can I use?&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;format&quot;&gt;&lt;a rel=&quot;noopener&quot; href=&quot;http://en.wikipedia.org/wiki/AVIF&quot;&gt;AVIF&lt;/a&gt;&lt;/td&gt;
  &lt;td data-th=&quot;transparency&quot;&gt;Yes&lt;/td&gt;
  &lt;td data-th=&quot;animation&quot;&gt;Yes&lt;/td&gt;
  &lt;td data-th=&quot;browser&quot;&gt;No. See &lt;a href=&quot;https://caniuse.com/avif&quot;&gt;Can I use?&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;There are two universally supported raster image formats: PNG and JPEG.
In addition to these formats, modern browsers support the newer format WebP, while only some support the newer AVIF format. Both of the newer formats offer better overall compression and more features. So, which format should you use?&lt;/p&gt;
&lt;p&gt;WebP and AVIF will generally provide better compression than older formats,
and should be used where possible.
You can use WebP or AVIF images along with a JPEG or PNG image as a fallback.
See &lt;a href=&quot;https://web.dev/serve-images-webp/&quot;&gt;Use WebP images&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;In terms of older image formats, consider the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do you need animation? Use &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;What about GIF? GIF limits the color palette to at most 256 colors,
and creates significantly larger file sizes than &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements. See
&lt;a href=&quot;https://web.dev/replace-gifs-with-videos/&quot;&gt;Replace animated GIFs with video&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need to preserve fine detail with highest resolution? Use PNG or lossless WebP.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;PNG does not apply any lossy compression algorithms beyond the choice of the size of the color palette.
As a result, it will produce the highest quality image,
but at a cost of significantly higher filesize than other formats. Use judiciously.&lt;/li&gt;
&lt;li&gt;WebP has a lossless encoding mode that may be more efficient than PNG.&lt;/li&gt;
&lt;li&gt;If the image asset contains imagery composed of geometric shapes, consider converting it to a vector (SVG) format!&lt;/li&gt;
&lt;li&gt;If the image asset contains text, stop and reconsider. Text in images is not selectable, searchable, or &amp;quot;zoomable&amp;quot;.
If you need to convey a custom look (for branding or other reasons), use a web font instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Are you optimizing a photo, screenshot, or a similar image asset? Use JPEG, lossy WebP, or lossy AVIF.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;JPEG uses a combination of lossy and lossless optimization to reduce filesize of the image asset. Try several JPEG quality levels to find the best quality versus filesize tradeoff for your asset.&lt;/li&gt;
&lt;li&gt;Lossy WebP or lossy AVIF may be acceptable JPEG alternatives, but be aware that WebP&#39;s lossy mode in particular discards some chroma information to achieve smaller images. This means that select colors may not be the same as an equivalent JPEG.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finally, note that if you are using a WebView to render content in your platform-specific application,
then you have full control of the client and can use WebP exclusively!
Facebook and many others use WebP to deliver all of their images within their applications—
the savings are definitely worth it.&lt;/p&gt;
&lt;h2 id=&quot;impact-on-largest-contentful-paint-lcp&quot;&gt;Impact on Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/choose-the-right-image-format/#impact-on-largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Images may be &lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;LCP candidates&lt;/a&gt;. That means the size of an image affects its &lt;a href=&quot;https://web.dev/optimize-lcp/#3-reduce-resource-load-time&quot;&gt;load time&lt;/a&gt;. When an image is an LCP candidate, efficiently encoding that image is crucial to improving LCP.&lt;/p&gt;
&lt;p&gt;You should strive to apply the advice given in this article so that the perceptual performance of a page is as fast as it can possibly be for all users. LCP is part of perceptual performance, as it measures how fast the largest (and therefore most perceivable) element on the page displays.&lt;/p&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Choose the correct level of compression</title>
    <link href="https://web.dev/compress-images/"/>
    <updated>2018-08-30T00:00:00Z</updated>
    <id>https://web.dev/compress-images/</id>
    <content type="html" mode="escaped">&lt;p&gt;Images often account for most of the downloaded bytes on a web page
and also often occupy a significant amount of visual space.
As a result,
optimizing images can often yield some of the largest byte savings and performance improvements for your website:
the fewer bytes the browser has to download,
the less competition there is for the client&#39;s bandwidth
and the faster the browser can download and render useful content on the screen.&lt;/p&gt;
&lt;p&gt;Image optimization is both an art and science:
an art because there is no one definitive answer for how best to compress an individual image,
and a science because there are many well developed techniques
and algorithms that can significantly reduce the size of an image.
Finding the optimal settings for your image requires careful analysis along many dimensions:
format capabilities, content of encoded data, quality, pixel dimensions, and more.&lt;/p&gt;
&lt;h2 id=&quot;optimizing-vector-images&quot;&gt;Optimizing vector images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/compress-images/#optimizing-vector-images&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All modern browsers support Scalable Vector Graphics (SVG),
which is an XML-based image format for two-dimensional graphics.
You can embed the SVG markup directly on the page
or as an external resource.
Most vector-based drawing software can create SVG files or you can
write them by hand directly in your favorite text editor.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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.2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;baseProfile&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;tiny&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Layer_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;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xmlns:&lt;/span&gt;xlink&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/1999/xlink&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;x&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 612 792&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xml:&lt;/span&gt;space&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preserve&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;g&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;XMLID_1_&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;black&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-miterlimit&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cy&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;40&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The above example renders the below simple circle shape with a black outline and red background
and was exported from Adobe Illustrator.&lt;/p&gt;

&lt;!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --&gt;
&lt;p&gt;&lt;svg version=&quot;1.2&quot; baseProfile=&quot;tiny&quot; id=&quot;Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; x=&quot;0px&quot; y=&quot;0px&quot; viewBox=&quot;0 0 612 120&quot; xml:space=&quot;preserve&quot;&gt;
&lt;g id=&quot;XMLID_1_&quot;&gt;
&lt;g&gt;
&lt;circle fill=&quot;red&quot; stroke=&quot;black&quot; stroke-width=&quot;2&quot; stroke-miterlimit=&quot;10&quot; cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;40&quot;&gt;&lt;/circle&gt;
&lt;/g&gt;
&lt;/g&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;p&gt;As you can tell, it contains a lot of metadata,
such as layer information, comments, and XML namespaces that are often unnecessary to render the asset in the browser.
As a result, it is always a good idea to minify your SVG files by running through a tool like &lt;a href=&quot;https://github.com/svg/svgo&quot; rel=&quot;noopener&quot;&gt;SVGO&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Case in point, SVGO reduces the size of the above SVG file generated by Illustrator by 58%,
taking it from 470 to 199 bytes.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;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.2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;baseProfile&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;tiny&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 612 792&lt;span class=&quot;token punctuation&quot;&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;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#000&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-miterlimit&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cy&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;40&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Because SVG is an XML-based format,
you can also apply GZIP compression to reduce its transfer size—make sure your server is configured to compress SVG assets!&lt;/p&gt;
&lt;p&gt;A raster image is simply a two-dimensional grid of individual &amp;quot;pixels&amp;quot;—for example,
a 100x100 pixel image is a sequence of 10,000 pixels.
In turn, each pixel stores the &amp;quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/RGBA_color_space&quot; rel=&quot;noopener&quot;&gt;RGBA&lt;/a&gt;&amp;quot; values:
(R) red channel, (G) green channel, (B) blue channel, and (A) alpha (transparency) channel.&lt;/p&gt;
&lt;p&gt;Internally, the browser allocates 256 values (shades) for each channel,
which translates to 8 bits per channel (2 ^ 8 = 256),
and 4 bytes per pixel (4 channels x 8 bits = 32 bits = 4 bytes).
As a result, if we know the dimensions of the grid we can easily calculate the filesize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;100x100 pixel image is composed of 10,000 pixels&lt;/li&gt;
&lt;li&gt;10,000 pixels x 4 bytes = 40,000 bytes&lt;/li&gt;
&lt;li&gt;40,000 bytes / 1024 = 39 KB&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; As an aside, regardless of the image format used to transfer the data from the server to the client, when the image is decoded by the browser, each pixel always occupies 4 bytes of memory. This can be an important constraint for large images and devices which do not have a lot of available memory —for example, low-end mobile devices. &lt;/div&gt;&lt;/aside&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
&lt;table&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Dimensions&lt;/th&gt;
    &lt;th&gt;Pixels&lt;/th&gt;
    &lt;th&gt;File size&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;dimensions&quot;&gt;100 x 100&lt;/td&gt;
  &lt;td data-th=&quot;pixels&quot;&gt;10,000&lt;/td&gt;
  &lt;td data-th=&quot;file size&quot;&gt;39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;dimensions&quot;&gt;200 x 200&lt;/td&gt;
  &lt;td data-th=&quot;pixels&quot;&gt;40,000&lt;/td&gt;
  &lt;td data-th=&quot;file size&quot;&gt;156 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;dimensions&quot;&gt;300 x 300&lt;/td&gt;
  &lt;td data-th=&quot;pixels&quot;&gt;90,000&lt;/td&gt;
  &lt;td data-th=&quot;file size&quot;&gt;351 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;dimensions&quot;&gt;500 x 500&lt;/td&gt;
  &lt;td data-th=&quot;pixels&quot;&gt;250,000&lt;/td&gt;
  &lt;td data-th=&quot;file size&quot;&gt;977 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;dimensions&quot;&gt;800 x 800&lt;/td&gt;
  &lt;td data-th=&quot;pixels&quot;&gt;640,000&lt;/td&gt;
  &lt;td data-th=&quot;file size&quot;&gt;2500 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;39 KB for a 100x100 pixel image may not seem like a big deal,
but the filesize quickly explodes for larger images and makes image assets both slow and expensive to download.
This post has so far only focused on the &amp;quot;uncompressed&amp;quot; image format.
Thankfully, a lot can be done to reduce the image file size.&lt;/p&gt;
&lt;p&gt;One simple strategy is to reduce the &amp;quot;bit-depth&amp;quot; of the image from 8 bits per channel to a smaller color palette:
8 bits per channel gives us 256 values per channel and 16,777,216 (256 ^ 3) colors in total.
What if you reduce the palette to 256 colors?
Then you would only need 8 bits in total for the RGB channels and immediately save two bytes per pixel—that&#39;s 50% compression savings over the original 4 bytes per pixel format!&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Compression artifacts&quot; decoding=&quot;async&quot; height=&quot;266&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 612px) 612px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ssek7uXzhs67joEbp0P8.png?auto=format&amp;w=1224 1224w&quot; width=&quot;612&quot; /&gt;
  &lt;figcaption&gt;Left to right (PNG): 32-bit (16M colors), 7-bit (128 colors), 5-bit (32 colors).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Complex scenes with gradual color transitions (for example, gradients or sky)
require larger color palettes to avoid visual artifacts such as the pixelated sky in the 5-bit asset.
On the other hand, if the image only uses a few colors,
then a large palette is simply wasting precious bits!&lt;/p&gt;
&lt;p&gt;Next, once you&#39;ve optimized the data stored in individual pixels you could get more clever and look at nearby pixels as well:
turns out, many images, and especially photos, have many nearby pixels with similar colors—
for example, the sky, repeating textures, and so on.
Using this information to your advantage the compressor can apply &lt;a href=&quot;https://en.wikipedia.org/wiki/Delta_encoding&quot; rel=&quot;noopener&quot;&gt;delta encoding&lt;/a&gt;
where instead of storing the individual values for each pixel,
you can store the difference between nearby pixels:
if the adjacent pixels are the same, then the delta is &amp;quot;zero&amp;quot; and you only need to store a single bit!
But why stop there…&lt;/p&gt;
&lt;p&gt;The human eye has different level of sensitivity to different colors:
you can optimize your color encoding to account for this by reducing or increasing the palette for those colors.
&amp;quot;Nearby&amp;quot; pixels form a two-dimensional grid. This means that each pixel has multiple neighbors:
you can use this fact to further improve delta encoding.
Instead of looking at just the immediate neighbors for each pixel,
you can look at larger blocks of nearby pixels and encode different blocks with different settings.&lt;/p&gt;
&lt;p&gt;As you can tell, image optimization gets complicated quickly (or fun, depending on your perspective),
and is an active area of academic and commercial research.
Images occupy a lot of bytes and there is a lot of value in developing better image compression techniques!
If you&#39;re curious to learn more, head to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Image_compression&quot; rel=&quot;noopener&quot;&gt;Wikipedia page&lt;/a&gt;,
or check out the &lt;a href=&quot;https://developers.google.com/speed/webp/docs/compression&quot; rel=&quot;noopener&quot;&gt;WebP compression techniques whitepaper&lt;/a&gt; for a hands-on example.&lt;/p&gt;
&lt;p&gt;So, once again, this is all great, but also very academic:
how does it help you to optimize images on your site?
Well, it&#39;s important to understand the shape of the problem: RGBA pixels, bit-depth, and various optimization techniques.
All of these concepts are critical to understand and keep in mind before you dive into the discussions of various raster image formats.&lt;/p&gt;
&lt;h2 id=&quot;lossless-versus-lossy-image-compression&quot;&gt;Lossless versus lossy image compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/compress-images/#lossless-versus-lossy-image-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For certain types of data, such as source code for a page, or an executable file,
it is critical that a compressor does not alter or lose any of the original information:
a single missing or wrong bit of data could completely change the meaning of the contents of the file,
or worse, break it entirely.
For some other types of data, such as images, audio, and video,
it may be perfectly acceptable to deliver an &amp;quot;approximate&amp;quot; representation of the original data.&lt;/p&gt;
&lt;p&gt;In fact, due to how the eye works,
we can often get away with discarding some information about each pixel in order to reduce the filesize of an image—
for example, our eyes have different sensitivity to different colors,
which means that we can use fewer bits to encode some colors.
As a result, a typical image optimization pipeline consists of two high level steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Image is processed with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Lossy_compression&quot; rel=&quot;noopener&quot;&gt;lossy&lt;/a&gt; filter that eliminates some pixel data.&lt;/li&gt;
&lt;li&gt;Image is processed with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Lossless_compression&quot; rel=&quot;noopener&quot;&gt;lossless&lt;/a&gt; filter that compresses the pixel data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first step is optional,
and the exact algorithm will depend on the particular image format,
but it is important to understand that any image can undergo a lossy compression step to reduce its size.
In fact, the difference between various image formats, such as GIF, PNG, JPEG, and others,
is in the combination of the specific algorithms they use (or omit) when applying the lossy and lossless steps.&lt;/p&gt;
&lt;p&gt;So, what is the &amp;quot;optimal&amp;quot; configuration of lossy and lossless optimization?
The answer depends on the image contents and your own criteria such as the tradeoff between filesize and artifacts introduced by lossy compression:
In some cases, you may want to skip lossy optimization to communicate intricate detail in its full fidelity.
In other cases, you may be able to apply aggressive lossy optimization to reduce the filesize of the image asset.
This is where your own judgment and context need to come into play—there is no one universal setting.&lt;/p&gt;
&lt;p&gt;As a hands-on example, when using a lossy format such as JPEG,
the compressor will typically expose a customizable &amp;quot;quality&amp;quot; setting
(for example, the quality slider provided by the &amp;quot;Save for Web&amp;quot; functionality in Adobe Photoshop),
which is typically a number between 1 and 100 that controls the inner workings of the specific collection of lossy and lossless algorithms.
For best results, experiment with various quality settings for your images,
and don&#39;t be afraid to dial down the quality—the visual results are often very good and the filesize savings can be quite large.&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; Note that quality levels for different image formats are not directly comparable due to differences in algorithms used to encode the image: quality 90 JPEG will produce a very different result than a quality 90 WebP. In fact, even quality levels for the same image format may produce visibly different output based on implementation of the compressor! &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;effects-of-image-compression-on-core-web-vitals&quot;&gt;Effects of image compression on Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/compress-images/#effects-of-image-compression-on-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because images are often candidates for &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt;, reducing the resource load time of an image can translate into better LCP in both &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#lab-data&quot;&gt;the lab&lt;/a&gt; and in &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#field-data&quot;&gt;the field&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When playing with compression settings on raster image formats, be sure to experiment with WebP and AVIF formats to see if you can deliver the same image in a small footprint as compared to older formats.&lt;/p&gt;
&lt;p&gt;You want to be careful not to &lt;em&gt;overcompress&lt;/em&gt; raster images, though. A good solution is to use an image optimization CDN to find the best compression settings for you, but an alternative may be to use tools like &lt;a href=&quot;https://github.com/google/butteraugli&quot; rel=&quot;noopener&quot;&gt;Butteraugli&lt;/a&gt; to estimate visual differences so that you don&#39;t encode images &lt;em&gt;too&lt;/em&gt; aggressively and lose too much quality.&lt;/p&gt;
&lt;h2 id=&quot;image-optimization-checklist&quot;&gt;Image optimization checklist &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/compress-images/#image-optimization-checklist&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some tips and techniques to keep in mind as you work on optimizing your images:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefer vector formats:&lt;/strong&gt; vector images are resolution and scale independent,
which makes them a perfect fit for the multi-device and high-resolution world.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minify and compress SVG assets:&lt;/strong&gt; XML markup produced by most drawing applications
often contains unnecessary metadata which can be removed;
Ensure that your servers are configured to apply GZIP compression for SVG assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer WebP or AVIF over older raster formats&lt;/strong&gt;: &lt;a href=&quot;https://web.dev/serve-images-webp/&quot;&gt;WebP&lt;/a&gt; and &lt;a href=&quot;https://web.dev/compress-images-avif/&quot;&gt;AVIF images&lt;/a&gt; will usually be far smaller than older image formats.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pick best raster image format:&lt;/strong&gt; determine your functional requirements and &lt;a href=&quot;https://web.dev/choose-the-right-image-format/&quot;&gt;select the one that suits each particular asset&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experiment with optimal quality settings for raster formats:&lt;/strong&gt; don&#39;t be afraid to dial down the &amp;quot;quality&amp;quot; settings,
the results are often very good and byte savings are significant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remove unnecessary image metadata:&lt;/strong&gt; many raster images contain unnecessary metadata about the asset:
geo information, camera information, and so on.
Use appropriate tools to strip this data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serve scaled images:&lt;/strong&gt; &lt;a href=&quot;https://web.dev/serve-images-with-correct-dimensions/&quot;&gt;resize images&lt;/a&gt; and ensure that the &amp;quot;display&amp;quot; size is as close as possible to the &amp;quot;natural&amp;quot; size of the image.
Pay close attention to large images in particular, as they account for largest overhead when resized!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate, automate, automate:&lt;/strong&gt; invest into automated tools and infrastructure that will ensure that all of your image assets are always optimized.&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>PageSpeed Rules and Recommendations</title>
    <link href="https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/"/>
    <updated>2018-08-17T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/</id>
    <content type="html" mode="escaped">&lt;p&gt;This guide examines PageSpeed Insights rules in context: what to pay attention to when optimizing the critical rendering path, and why.&lt;/p&gt;
&lt;h2 id=&quot;eliminate-render-blocking-javascript-and-css&quot;&gt;Eliminate render-blocking JavaScript and CSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#eliminate-render-blocking-javascript-and-css&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To deliver the fastest time to first render, minimize and (where possible) eliminate the number of critical resources on the page, minimize the number of downloaded critical bytes, and optimize the critical path length.&lt;/p&gt;
&lt;h2 id=&quot;optimize-javascript-use&quot;&gt;Optimize JavaScript use &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#optimize-javascript-use&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JavaScript resources are parser blocking by default unless marked as &lt;code&gt;async&lt;/code&gt; or added via a special JavaScript snippet. Parser blocking JavaScript forces the browser to wait for the CSSOM and pauses construction of the DOM, which in turn can significantly delay the time to first render.&lt;/p&gt;
&lt;h3 id=&quot;prefer-asynchronous-javascript-resources&quot;&gt;Prefer asynchronous JavaScript resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#prefer-asynchronous-javascript-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Asynchronous resources unblock the document parser and allow the browser to avoid blocking on CSSOM prior to executing the script. Often, if the script can use the &lt;code&gt;async&lt;/code&gt; attribute, it also means it is not essential for the first render. Consider loading scripts asynchronously after the initial render.&lt;/p&gt;
&lt;h3 id=&quot;avoid-synchronous-server-calls&quot;&gt;Avoid synchronous server calls &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#avoid-synchronous-server-calls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the &lt;code&gt;navigator.sendBeacon()&lt;/code&gt; method to limit data sent by XMLHttpRequests in
&lt;code&gt;unload&lt;/code&gt; handlers. Because many browsers require such requests to be
synchronous, they can slow page transitions, sometimes noticeably. The following
code shows how to use &lt;code&gt;navigator.sendBeacon()&lt;/code&gt; to send data to the server in the
&lt;code&gt;pagehide&lt;/code&gt; handler instead of in the &lt;code&gt;unload&lt;/code&gt; handler.&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;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&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;        window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pagehide&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;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;logData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendBeacon&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;https://putsreq.herokuapp.com/Dt7t2QzUkG18aDTMMcop&#39;&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;Sent by a beacon!&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The new &lt;code&gt;fetch()&lt;/code&gt; method provides an easy way to asynchronously request data. Because it is not available everywhere yet, you should use feature detection to test for its presence before use. This method processes responses with Promises rather than multiple event handlers. Unlike the response to an XMLHttpRequest, a fetch response is a stream object starting in Chrome 43. This means that a call to &lt;code&gt;json()&lt;/code&gt; also returns a Promise.&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;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&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;./api/some.json&#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 function&quot;&gt;then&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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;token punctuation&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;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;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;Looks like there was a problem. Status Code: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;  response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token comment&quot;&gt;// Examine the text in the response&lt;/span&gt;&lt;br /&gt;          response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;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 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;data&lt;/span&gt;&lt;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;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&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;err&lt;/span&gt;&lt;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;Fetch Error :-S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span 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 operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;fetch()&lt;/code&gt; method can also handle POST requests.&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;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&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;url&lt;span class=&quot;token punctuation&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;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;post&#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;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Content-type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/x-www-form-urlencoded; charset=UTF-8&quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;foo=bar&amp;amp;lorem=ipsum&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;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 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 comment&quot;&gt;// Additional code });&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;defer-parsing-javascript&quot;&gt;Defer parsing JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#defer-parsing-javascript&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To minimize the amount of work the browser has to perform to render the page, defer any non-essential scripts that are not critical to constructing the visible content for the initial render.&lt;/p&gt;
&lt;h3 id=&quot;avoid-long-running-javascript&quot;&gt;Avoid long running JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#avoid-long-running-javascript&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Long running JavaScript blocks the browser from constructing the DOM, CSSOM, and rendering the page, so defer until later any initialization logic and functionality that is non-essential for the first render. If a long initialization sequence needs to run, consider splitting it into several stages to allow the browser to process other events in between.&lt;/p&gt;
&lt;h2 id=&quot;optimize-css-use&quot;&gt;Optimize CSS Use &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#optimize-css-use&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CSS is required to construct the render tree and JavaScript often blocks on CSS during initial construction of the page. Ensure that any non-essential CSS is marked as non-critical (for example, print and other media queries), and that the amount of critical CSS and the time to deliver it is as small as possible.&lt;/p&gt;
&lt;h3 id=&quot;put-css-in-the-document-head&quot;&gt;Put CSS in the document head &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#put-css-in-the-document-head&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Specify all CSS resources as early as possible within the HTML document so that the browser can discover the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags and dispatch the request for the CSS as soon as possible.&lt;/p&gt;
&lt;h3 id=&quot;avoid-css-imports&quot;&gt;Avoid CSS imports &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#avoid-css-imports&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The CSS import (&lt;code&gt;@import&lt;/code&gt;) directive enables one stylesheet to import rules from another stylesheet file. However, avoid these directives because they introduce additional roundtrips into the critical path: the imported CSS resources are discovered only after the CSS stylesheet with the &lt;code&gt;@import&lt;/code&gt; rule itself is received and parsed.&lt;/p&gt;
&lt;h3 id=&quot;inline-render-blocking-css&quot;&gt;Inline render-blocking CSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#inline-render-blocking-css&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For best performance, you may want to consider inlining the critical CSS directly into the HTML document. This eliminates additional roundtrips in the critical path and if done correctly can deliver a &amp;quot;one roundtrip&amp;quot; critical path length where only the HTML is a blocking resource.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Introduction to HTTP/2</title>
    <link href="https://web.dev/performance-http2/"/>
    <updated>2016-09-29T00:00:00Z</updated>
    <id>https://web.dev/performance-http2/</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; The following content is an excerpt from &lt;a href=&quot;http://shop.oreilly.com/product/0636920028048.do&quot;&gt;High Performance Browser Networking&lt;/a&gt; (O&#39;Reilly, Ilya Grigorik). For full version and related content, see &lt;a href=&quot;https://hpbn.co/&quot;&gt;hpbn.co&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;HTTP/2 will make our applications faster, simpler, and more robust — a rare
combination — by allowing us to undo many of the HTTP/1.1 workarounds previously
done within our applications and address these concerns within the transport
layer itself. Even better, it also opens up a number of entirely new
opportunities to optimize our applications and improve performance!&lt;/p&gt;
&lt;p&gt;The primary goals for HTTP/2 are to reduce latency by enabling full request and
response multiplexing, minimize protocol overhead via efficient compression of
HTTP header fields, and add support for request prioritization and server push.
To implement these requirements, there is a large supporting cast of other
protocol enhancements, such as new flow control, error handling, and upgrade
mechanisms, but these are the most important features that every web developer
should understand and leverage in their applications.&lt;/p&gt;
&lt;p&gt;HTTP/2 does not modify the application semantics of HTTP in any way. All the
core concepts, such as HTTP methods, status codes, URIs, and header fields,
remain in place. Instead, HTTP/2 modifies how the data is formatted (framed) and
transported between the client and server, both of which manage the entire
process, and hides all the complexity from our applications within the new
framing layer. As a result, all existing applications can be delivered without
modification.&lt;/p&gt;
&lt;h2 id=&quot;why-not-http12&quot;&gt;Why not HTTP/1.2? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#why-not-http12&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To achieve the performance goals set by the HTTP Working Group, HTTP/2
introduces a new binary framing layer that is not backward compatible with
previous HTTP/1.x servers and clients—hence the major protocol version increment
to HTTP/2.&lt;/p&gt;
&lt;p&gt;That said, unless you are implementing a web server (or a custom client) by
working with raw TCP sockets, then you won’t see any difference: all the new,
low-level framing is performed by the client and server on your behalf. The only
observable differences will be improved performance and availability of new
capabilities like request prioritization, flow control, and server push.&lt;/p&gt;
&lt;h2 id=&quot;a-brief-history-of-spdy-and-http2&quot;&gt;A brief history of SPDY and HTTP/2 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#a-brief-history-of-spdy-and-http2&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SPDY was an experimental protocol, developed at Google and announced in
mid 2009, whose primary goal was to try to reduce the load latency of web pages
by addressing some of the well-known performance limitations of HTTP/1.1.
Specifically, the outlined project goals were set as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Target a 50% reduction in page load time (PLT).&lt;/li&gt;
&lt;li&gt;Avoid the need for any changes to content by website authors.&lt;/li&gt;
&lt;li&gt;Minimize deployment complexity, and avoid changes in network infrastructure.&lt;/li&gt;
&lt;li&gt;Develop this new protocol in partnership with the open-source community.&lt;/li&gt;
&lt;li&gt;Gather real performance data to (in)validate the experimental protocol.&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 achieve the 50% PLT improvement, SPDY aimed to make more efficient use of the underlying TCP connection by introducing a new binary framing layer to enable request and response multiplexing, prioritization, and header compression; see &lt;a href=&quot;https://hpbn.co/primer-on-web-performance/#latency-as-a-performance-bottleneck&quot;&gt;Latency as a Performance Bottleneck&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Not long after the initial announcement, Mike Belshe and Roberto Peon, both
software engineers at Google, shared their first results, documentation, and
source code for the experimental implementation of the new SPDY protocol:&lt;/p&gt;
&lt;p&gt;So far we have only tested SPDY in lab conditions. The initial results are
very encouraging: when we download the top 25 websites over simulated home
network connections, we see a significant improvement in performance—pages
loaded up to 55% faster.
&lt;a href=&quot;https://blog.chromium.org/2009/11/2x-faster-web.html&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;(Chromium Blog)&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fast-forward to 2012 and the new experimental protocol was supported in Chrome,
Firefox, and Opera, and a rapidly growing number of sites, both large (for example,
Google, Twitter, Facebook) and small, were deploying SPDY within their
infrastructure. In effect, SPDY was on track to become a de facto standard
through growing industry adoption.&lt;/p&gt;
&lt;p&gt;Observing this trend, the HTTP Working Group (HTTP-WG) kicked off a new
effort to take the lessons learned from SPDY, build and improve on them, and
deliver an official &amp;quot;HTTP/2&amp;quot; standard. A new charter was drafted, an open call
for HTTP/2 proposals was made, and after a lot of discussion within the working
group, the SPDY specification was adopted as a starting point for the new HTTP/2
protocol.&lt;/p&gt;
&lt;p&gt;Over the next few years SPDY and HTTP/2 continued to coevolve in parallel,
with SPDY acting as an experimental branch that was used to test new features
and proposals for the HTTP/2 standard. What looks good on paper may not work in
practice, and vice versa, and SPDY offered a route to test and evaluate each
proposal before its inclusion in the HTTP/2 standard. In the end, this process
spanned three years and resulted in a over a dozen intermediate drafts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;March 2012: Call for proposals for HTTP/2&lt;/li&gt;
&lt;li&gt;November 2012: First draft of HTTP/2 (based on SPDY)&lt;/li&gt;
&lt;li&gt;August 2014: HTTP/2 draft-17 and HPACK draft-12 are published&lt;/li&gt;
&lt;li&gt;August 2014: Working Group last call for HTTP/2&lt;/li&gt;
&lt;li&gt;February 2015: IESG approved HTTP/2 and HPACK drafts&lt;/li&gt;
&lt;li&gt;May 2015: RFC 7540 (HTTP/2) and RFC 7541 (HPACK) are published&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In early 2015 the IESG reviewed and approved the new HTTP/2 standard for
publication. Shortly after that, the Google Chrome team announced their schedule
to deprecate SPDY and NPN extension for TLS:&lt;/p&gt;
&lt;p&gt;HTTP/2&#39;s primary changes from HTTP/1.1 focus on improved performance. Some key
features such as multiplexing, header compression, prioritization and protocol
negotiation evolved from work done in an earlier open, but non-standard
protocol named SPDY. Chrome has supported SPDY since Chrome 6, but since most
of the benefits are present in HTTP/2, it’s time to say goodbye. We plan to
remove support for SPDY in early 2016, and to also remove support for the TLS
extension named NPN in favor of ALPN in Chrome at the same time. Server
developers are strongly encouraged to move to HTTP/2 and ALPN.&lt;/p&gt;
&lt;p&gt;We’re happy to have contributed to the open standards process that led to
HTTP/2, and hope to see wide adoption given the broad industry engagement on
standardization and implementation. &lt;a href=&quot;https://blog.chromium.org/2015/02/hello-http2-goodbye-spdy.html&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;(Chromium
Blog)&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The coevolution of SPDY and HTTP/2 enabled server, browser, and site developers
to gain real-world experience with the new protocol as it was being developed.
As a result, the HTTP/2 standard is one of the best and most extensively tested
standards right out of the gate. By the time HTTP/2 was approved by the IESG,
there were dozens of thoroughly tested and production-ready client and server
implementations. In fact, just weeks after the final protocol was approved, many
users were already enjoying its benefits as several popular browsers (and many
sites) deployed full HTTP/2 support.&lt;/p&gt;
&lt;h2 id=&quot;design-and-technical-goals&quot;&gt;Design and technical goals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#design-and-technical-goals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Earlier versions of the HTTP protocol were intentionally designed for simplicity
of implementation: HTTP/0.9 was a one-line protocol to bootstrap the World Wide
Web; HTTP/1.0 documented the popular extensions to HTTP/0.9 in an informational
standard; HTTP/1.1 introduced an official IETF standard; see
&lt;a href=&quot;https://hpbn.co/brief-history-of-http/&quot; rel=&quot;noopener&quot;&gt;Brief History of HTTP&lt;/a&gt;.
As such, HTTP/0.9-1.x delivered exactly what it set out to do: HTTP is one of
the most widely adopted application protocols on the Internet.&lt;/p&gt;
&lt;p&gt;Unfortunately, implementation simplicity also came at a cost of application
performance: HTTP/1.x clients need to use multiple connections to achieve
concurrency and reduce latency; HTTP/1.x does not compress request and response
headers, causing unnecessary network traffic; HTTP/1.x does not allow effective
resource prioritization, resulting in poor use of the underlying TCP connection;
and so on.&lt;/p&gt;
&lt;p&gt;These limitations were not fatal, but as the web applications continued to grow
in their scope, complexity, and importance in our everyday lives, they imposed a
growing burden on both the developers and users of the web, which is the exact
gap that HTTP/2 was designed to address:&lt;/p&gt;
&lt;p&gt;HTTP/2 enables a more efficient use of network resources and a reduced
perception of latency by introducing header field compression and allowing
multiple concurrent exchanges on the same connection… Specifically, it allows
interleaving of request and response messages on the same connection and uses
an efficient coding for HTTP header fields. It also allows prioritization of
requests, letting more important requests complete more quickly, further
improving performance.&lt;/p&gt;
&lt;p&gt;The resulting protocol is more friendly to the network, because fewer TCP
connections can be used in comparison to HTTP/1.x. This means less competition
with other flows, and longer-lived connections, which in turn leads to better
utilization of available network capacity. Finally, HTTP/2 also enables more
efficient processing of messages through use of binary message framing.
&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-httpbis-http2-17&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;(Hypertext Transfer Protocol version 2, Draft 17)&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is important to note that HTTP/2 is extending, not replacing, the previous
HTTP standards. The application semantics of HTTP are the same, and no changes
were made to the offered functionality or core concepts such as HTTP methods,
status codes, URIs, and header fields. These changes were explicitly out of scope
for the HTTP/2 effort. That said, while the high-level API remains the same, it
is important to understand how the low-level changes address the performance
limitations of the previous protocols. Let’s take a brief tour of the binary
framing layer and its features.&lt;/p&gt;
&lt;h2 id=&quot;binary-framing-layer&quot;&gt;Binary framing layer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#binary-framing-layer&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the core of all performance enhancements of HTTP/2 is the new binary framing
layer, which dictates how the HTTP messages are encapsulated and transferred
between the client and server.&lt;/p&gt;
&lt;img alt=&quot;HTTP/2 binary framing layer&quot; decoding=&quot;async&quot; height=&quot;150&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2a2cw0nAXe9Mi5txM4Mw.svg&quot; width=&quot;291&quot; /&gt;
&lt;p&gt;The &amp;quot;layer&amp;quot; refers to a design choice to introduce a new optimized encoding
mechanism between the socket interface and the higher HTTP API exposed to our
applications: the HTTP semantics, such as verbs, methods, and headers, are
unaffected, but the way they are encoded while in transit is different.
Unlike the newline delimited plaintext HTTP/1.x protocol, all HTTP/2
communication is split into smaller messages and frames, each of which is
encoded in binary format.&lt;/p&gt;
&lt;p&gt;As a result, both client and server must use the new binary encoding mechanism
to understand each other: an HTTP/1.x client won’t understand an HTTP/2 only
server, and vice versa. Thankfully, our applications remain blissfully unaware
of all these changes, as the client and server perform all the necessary framing
work on our behalf.&lt;/p&gt;
&lt;h2 id=&quot;streams,-messages,-and-frames&quot;&gt;Streams, messages, and frames &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#streams,-messages,-and-frames&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The introduction of the new binary framing mechanism changes how the data is
exchanged between the client and server. To describe this process, let’s
familiarize ourselves with the HTTP/2 terminology:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Stream&lt;/em&gt;: A bidirectional flow of bytes within an established connection,
which may carry one or more messages.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Message&lt;/em&gt;: A complete sequence of frames that map to a logical request or response message.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Frame&lt;/em&gt;: The smallest unit of communication in HTTP/2, each containing a frame header, which
at a minimum identifies the stream to which the frame belongs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The relation of these terms can be summarized as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All communication is performed over a single TCP connection that can carry any number of
bidirectional streams.&lt;/li&gt;
&lt;li&gt;Each stream has a unique identifier and optional priority information that is used to carry
bidirectional messages.&lt;/li&gt;
&lt;li&gt;Each message is a logical HTTP message, such as a request, or response, which consists of
one or more frames.&lt;/li&gt;
&lt;li&gt;The frame is the smallest unit of communication that carries a specific type of data—e.g.,
HTTP headers, message payload, and so on. Frames from different streams may be interleaved
and then reassembled via the embedded stream identifier in the header of each frame.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;HTTP/2 streams, messages, and frames&quot; decoding=&quot;async&quot; height=&quot;150&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/0bfdEw00aKXFDxT0yEKt.svg&quot; width=&quot;184&quot; /&gt;
&lt;p&gt;In short, HTTP/2 breaks down the HTTP protocol communication into an exchange of
binary-encoded frames, which are then mapped to messages that belong to a
particular stream, all of which are multiplexed within a single TCP
connection. This is the foundation that enables all other features and
performance optimizations provided by the HTTP/2 protocol.&lt;/p&gt;
&lt;h2 id=&quot;request-and-response-multiplexing&quot;&gt;Request and response multiplexing &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#request-and-response-multiplexing&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With HTTP/1.x, if the client wants to make multiple parallel requests to improve
performance, then multiple TCP connections must be used (see
&lt;a href=&quot;https://hpbn.co/http1x/#using-multiple-tcp-connections&quot; rel=&quot;noopener&quot;&gt;Using Multiple TCP Connections&lt;/a&gt;
). This behavior is a direct consequence of the HTTP/1.x delivery model, which
ensures that only one response can be delivered at a time (response queuing) per
connection. Worse, this also results in head-of-line blocking and inefficient
use of the underlying TCP connection.&lt;/p&gt;
&lt;p&gt;The new binary framing layer in HTTP/2 removes these limitations, and enables
full request and response multiplexing, by allowing the client and server to
break down an HTTP message into independent frames, interleave them, and then
reassemble them on the other end.&lt;/p&gt;
&lt;img alt=&quot;HTTP/2 request and response multiplexing within a shared connection&quot; decoding=&quot;async&quot; height=&quot;83&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4RwALfscCwB7MDa1bGsV.svg&quot; width=&quot;300&quot; /&gt;
&lt;p&gt;The snapshot captures multiple streams in flight within the same connection. The
client is transmitting a &lt;code&gt;DATA&lt;/code&gt; frame (stream 5) to the server, while the server
is transmitting an interleaved sequence of frames to the client for streams 1
and 3. As a result, there are three parallel streams in flight.&lt;/p&gt;
&lt;p&gt;The ability to break down an HTTP message into independent frames, interleave
them, and then reassemble them on the other end is the single most important
enhancement of HTTP/2. In fact, it introduces a ripple effect of numerous
performance benefits across the entire stack of all web technologies, enabling
us to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interleave multiple requests in parallel without blocking on any one.&lt;/li&gt;
&lt;li&gt;Interleave multiple responses in parallel without blocking on any one.&lt;/li&gt;
&lt;li&gt;Use a single connection to deliver multiple requests and responses in parallel.&lt;/li&gt;
&lt;li&gt;Remove unnecessary HTTP/1.x workarounds (see
&lt;a href=&quot;https://hpbn.co/optimizing-application-delivery/#optimizing-for-http1x&quot; rel=&quot;noopener&quot;&gt;Optimizing for HTTP/1.x&lt;/a&gt;,
such as concatenated files, image sprites, and domain sharding).&lt;/li&gt;
&lt;li&gt;Deliver lower page load times by eliminating unnecessary latency and improving
utilization of available network capacity.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;And much more…&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new binary framing layer in HTTP/2 resolves the head-of-line blocking
problem found in HTTP/1.x and eliminates the need for multiple connections to
enable parallel processing and delivery of requests and responses. As a result,
this makes our applications faster, simpler, and cheaper to deploy.&lt;/p&gt;
&lt;h2 id=&quot;stream-prioritization&quot;&gt;Stream prioritization &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#stream-prioritization&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once an HTTP message can be split into many individual frames, and we allow for
frames from multiple streams to be multiplexed, the order in which the frames
are interleaved and delivered both by the client and server becomes a critical
performance consideration. To facilitate this, the HTTP/2 standard allows each
stream to have an associated weight and dependency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each stream may be assigned an integer weight between 1 and 256.&lt;/li&gt;
&lt;li&gt;Each stream may be given an explicit dependency on another stream.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The combination of stream dependencies and weights allows the client to
construct and communicate a &amp;quot;prioritization tree&amp;quot; that expresses how it would
prefer to receive responses. In turn, the server can use this information to
prioritize stream processing by controlling the allocation of CPU, memory, and
other resources, and once the response data is available, allocation of
bandwidth to ensure optimal delivery of high-priority responses to the client.&lt;/p&gt;
&lt;img alt=&quot;HTTP/2 stream dependencies and weights&quot; decoding=&quot;async&quot; height=&quot;127&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ydLldhPadjknvvrUiCai.svg&quot; width=&quot;300&quot; /&gt;
&lt;p&gt;A stream dependency within HTTP/2 is declared by referencing the unique
identifier of another stream as its parent; if the identifier is omitted the
stream is said to be dependent on the &amp;quot;root stream&amp;quot;. Declaring a stream
dependency indicates that, if possible, the parent stream should be allocated
resources ahead of its dependencies. In other words, &amp;quot;Please process and deliver
response D before response C&amp;quot;.&lt;/p&gt;
&lt;p&gt;Streams that share the same parent (in other words, sibling streams) should be allocated
resources in proportion to their weight. For example, if stream A has a weight
of 12 and its one sibling B has a weight of 4, then to determine the proportion
of the resources that each of these streams should receive:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sum all the weights: &lt;code&gt;4 + 12 = 16&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Divide each stream weight by the total weight: &lt;code&gt;A = 12/16, B = 4/16&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus, stream A should receive three-quarters and stream B should receive one-
quarter of available resources; stream B should receive one-third of the
resources allocated to stream A. Let’s work through a few more hands-on examples
in the image above. From left to right:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Neither stream A nor B specifies a parent dependency and are said to be dependent
on the implicit &amp;quot;root stream&amp;quot;; A has a weight of 12, and B has a weight of 4.
Thus, based on proportional weights: stream B should receive one-third of the
resources allocated to stream A.&lt;/li&gt;
&lt;li&gt;Stream D is dependent on the root stream; C is dependent on D. Thus, D should
receive full allocation of resources ahead of C. The weights are inconsequential
because C’s dependency communicates a stronger preference.&lt;/li&gt;
&lt;li&gt;Stream D should receive full allocation of resources ahead of C; C should receive
full allocation of resources ahead of A and B; stream B should receive one-third of
the resources allocated to stream A.&lt;/li&gt;
&lt;li&gt;Stream D should receive full allocation of resources ahead of E and C; E and C
should receive equal allocation ahead of A and B; A and B should receive proportional
allocation based on their weights.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As the above examples illustrate, the combination of stream dependencies and
weights provides an expressive language for resource prioritization, which is a
critical feature for improving browsing performance where we have many resource
types with different dependencies and weights. Even better, the HTTP/2 protocol
also allows the client to update these preferences at any point, which enables
further optimizations in the browser. In other words, we can change dependencies
and reallocate weights in response to user interaction and other signals.&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; Stream dependencies and weights express a transport preference, not a requirement, and as such do not guarantee a particular processing or transmission order. That is, the client cannot force the server to process the stream in a particular order using stream prioritization. While this may seem counterintuitive, it is in fact the desired behavior. We do not want to block the server from making progress on a lower priority resource if a higher priority resource is blocked. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;one-connection-per-origin&quot;&gt;One connection per origin &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#one-connection-per-origin&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the new binary framing mechanism in place, HTTP/2 no longer needs multiple
TCP connections to multiplex streams in parallel; each stream is split into many
frames, which can be interleaved and prioritized. As a result, all HTTP/2
connections are persistent, and only one connection per origin is required,
which offers numerous performance benefits.&lt;/p&gt;
&lt;p&gt;For both SPDY and HTTP/2 the killer feature is arbitrary multiplexing on a
single well congestion controlled channel. It amazes me how important this is
and how well it works. One great metric around that which I enjoy is the
fraction of connections created that carry just a single HTTP transaction (and
thus make that transaction bear all the overhead). For HTTP/1 74% of our
active connections carry just a single transaction—persistent connections just
aren’t as helpful as we all want. But in HTTP/2 that number plummets to 25%.
That’s a huge win for overhead reduction. &lt;a href=&quot;http://bitsup.blogspot.co.uk/2015/02/http2-is-live-in-firefox.html&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;(HTTP/2 is Live in Firefox, Patrick
McManus)&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most HTTP transfers are short and bursty, whereas TCP is optimized for long-
lived, bulk data transfers. By reusing the same connection, HTTP/2 is able to
both make more efficient use of each TCP connection, and also significantly
reduce the overall protocol overhead. Further, the use of fewer connections
reduces the memory and processing footprint along the full connection path
(in other words, client, intermediaries, and origin servers). This reduces the overall
operational costs and improves network utilization and capacity. As a result,
the move to HTTP/2 should not only reduce network latency, but also help
improve throughput and reduce the operational costs.&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; Reduced number of connections is a particularly important feature for improving performance of HTTPS deployments: this translates to fewer expensive TLS handshakes, better session reuse, and an overall reduction in required client and server resources. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;flow-control&quot;&gt;Flow control &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#flow-control&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Flow control is a mechanism to prevent the sender from overwhelming the receiver
with data it may not want or be able to process: the receiver may be busy, under
heavy load, or may only be willing to allocate a fixed amount of resources for a
particular stream. For example, the client may have requested a large video
stream with high priority, but the user has paused the video and the client now
wants to pause or throttle its delivery from the server to avoid fetching and
buffering unnecessary data. Alternatively, a proxy server may have fast
downstream and slow upstream connections and similarly wants to regulate how
quickly the downstream delivers data to match the speed of upstream to control
its resource usage; and so on.&lt;/p&gt;
&lt;p&gt;Do the above requirements remind you of TCP flow control? They should, as the
problem is effectively identical (see
&lt;a href=&quot;https://hpbn.co/building-blocks-of-tcp/#flow-control&quot; rel=&quot;noopener&quot;&gt;Flow Control&lt;/a&gt;). However,
because the HTTP/2 streams are multiplexed within a single TCP connection, TCP
flow control is both not granular enough, and does not provide the necessary
application-level APIs to regulate the delivery of individual streams. To
address this, HTTP/2 provides a set of simple building blocks that allow the
client and server to implement their own stream- and connection-level flow
control:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flow control is directional. Each receiver may choose to set any window size
that it desires for each stream and the entire connection.&lt;/li&gt;
&lt;li&gt;Flow control is credit-based. Each receiver advertises its initial connection
and stream flow control window (in bytes), which is reduced whenever the
sender emits a &lt;code&gt;DATA&lt;/code&gt; frame and incremented via a &lt;code&gt;WINDOW_UPDATE&lt;/code&gt; frame sent
by the receiver.&lt;/li&gt;
&lt;li&gt;Flow control cannot be disabled. When the HTTP/2 connection is established the
client and server exchange &lt;code&gt;SETTINGS&lt;/code&gt; frames, which set the flow control window
sizes in both directions. The default value of the flow control window is set
to 65,535 bytes, but the receiver can set a large maximum window size
(&lt;code&gt;2^31-1&lt;/code&gt; bytes) and maintain it by sending a &lt;code&gt;WINDOW_UPDATE&lt;/code&gt; frame whenever any
data is received.&lt;/li&gt;
&lt;li&gt;Flow control is hop-by-hop, not end-to-end. That is, an intermediary can use it
to control resource use and implement resource allocation mechanisms based on
own criteria and heuristics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTTP/2 does not specify any particular algorithm for implementing flow control.
Instead, it provides the simple building blocks and defers the implementation to
the client and server, which can use it to implement custom strategies to
regulate resource use and allocation, as well as implement new delivery
capabilities that may help improve both the real and perceived performance (see
&lt;a href=&quot;https://hpbn.co/primer-on-web-performance/#speed-performance-and-human-perception&quot; rel=&quot;noopener&quot;&gt;Speed, Performance, and Human Perception&lt;/a&gt;)
of our web applications.&lt;/p&gt;
&lt;p&gt;For example, application-layer flow control allows the browser to fetch only a
part of a particular resource, put the fetch on hold by reducing the stream flow
control window down to zero, and then resume it later. In other words, it allows
the browser to fetch a preview or first scan of an image, display it and allow
other high priority fetches to proceed, and resume the fetch once more critical
resources have finished loading.&lt;/p&gt;
&lt;h2 id=&quot;server-push&quot;&gt;Server push &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#server-push&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another powerful new feature of HTTP/2 is the ability of the server to send
multiple responses for a single client request. That is, in addition to the
response to the original request, the server can push additional resources to
the client (Figure 12-5), without the client having to request each one
explicitly.&lt;/p&gt;
&lt;img alt=&quot;Server initiates new streams (promises) for push resources&quot; decoding=&quot;async&quot; height=&quot;117&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/o6lgFK9DiyJmdWwyJnyy.svg&quot; width=&quot;300&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; HTTP/2 breaks away from the strict request-response semantics and enables one-to-many and server-initiated push workflows that open up a world of new interaction possibilities both within and outside the browser. This is an enabling feature that will have important long-term consequences both for how we think about the protocol, and where and how it is used. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Why would we need such a mechanism in a browser? A typical web application
consists of dozens of resources, all of which are discovered by the client by
examining the document provided by the server. As a result, why not eliminate
the extra latency and let the server push the associated resources ahead of
time? The server already knows which resources the client will require; that’s
server push.&lt;/p&gt;
&lt;p&gt;In fact, if you have ever inlined a CSS, JavaScript, or any other asset via a
data URI (see &lt;a href=&quot;https://hpbn.co/http1x/#resource-inlining&quot; rel=&quot;noopener&quot;&gt;Resource Inlining&lt;/a&gt;),
then you already have hands-on experience with server push. By manually inlining
the resource into the document, we are, in effect, pushing that resource to the
client, without waiting for the client to request it. With HTTP/2 we can achieve
the same results, but with additional performance benefits. Push resources can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cached by the client&lt;/li&gt;
&lt;li&gt;Reused across different pages&lt;/li&gt;
&lt;li&gt;Multiplexed alongside other resources&lt;/li&gt;
&lt;li&gt;Prioritized by the server&lt;/li&gt;
&lt;li&gt;Declined by the client&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pushpromise-101&quot;&gt;PUSH_PROMISE 101 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#pushpromise-101&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All server push streams are initiated via &lt;code&gt;PUSH_PROMISE&lt;/code&gt; frames, which signal the
server’s intent to push the described resources to the client and need to be
delivered ahead of the response data that requests the pushed resources. This
delivery order is critical: the client needs to know which resources the server
intends to push to avoid creating duplicate requests for these
resources. The simplest strategy to satisfy this requirement is to send all
&lt;code&gt;PUSH_PROMISE&lt;/code&gt; frames, which contain just the HTTP headers of the promised
resource, ahead of the parent’s response (in other words, &lt;code&gt;DATA&lt;/code&gt; frames).&lt;/p&gt;
&lt;p&gt;Once the client receives a &lt;code&gt;PUSH_PROMISE&lt;/code&gt; frame it has the option to decline the
stream (via a &lt;code&gt;RST_STREAM&lt;/code&gt; frame) if it wants to. (This might occur for example
because the resource is already in cache.) This is an important improvement over
HTTP/1.x. By contrast, the use of resource inlining, which is a popular
&amp;quot;optimization&amp;quot; for HTTP/1.x, is equivalent to a &amp;quot;forced push&amp;quot;: the client cannot
opt-out, cancel it, or process the inlined resource individually.&lt;/p&gt;
&lt;p&gt;With HTTP/2 the client remains in full control of how server push is used. The
client can limit the number of concurrently pushed streams; adjust the initial
flow control window to control how much data is pushed when the stream is first
opened; or disable server push entirely. These preferences are communicated via
the &lt;code&gt;SETTINGS&lt;/code&gt; frames at the beginning of the HTTP/2 connection and may be updated
at any time.&lt;/p&gt;
&lt;p&gt;Each pushed resource is a stream that, unlike an inlined resource, allows it to
be individually multiplexed, prioritized, and processed by the client. The only
security restriction, as enforced by the browser, is that pushed resources must
obey the same-origin policy: the server must be authoritative for the provided
content.&lt;/p&gt;
&lt;h2 id=&quot;header-compression&quot;&gt;Header compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#header-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each HTTP transfer carries a set of headers that describe the transferred
resource and its properties. In HTTP/1.x, this metadata is always sent as plain
text and adds anywhere from 500–800 bytes of overhead per transfer, and
sometimes kilobytes more if HTTP cookies are being used. (See
&lt;a href=&quot;https://hpbn.co/http1x/#measuring-and-controlling-protocol-overhead&quot; rel=&quot;noopener&quot;&gt;Measuring and Controlling Protocol Overhead&lt;/a&gt;
.) To reduce this overhead and improve performance, HTTP/2 compresses request
and response header metadata using the HPACK compression format that uses two
simple but powerful techniques:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It allows the transmitted header fields to be encoded via a static Huffman
code, which reduces their individual transfer size.&lt;/li&gt;
&lt;li&gt;It requires that both the client and server maintain and update an indexed
list of previously seen header fields (in other words, it establishes a shared
compression context), which is then used as a reference to efficiently encode
previously transmitted values.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Huffman coding allows the individual values to be compressed when transferred,
and the indexed list of previously transferred values allows us to encode
duplicate values by transferring index values that can be used to efficiently
look up and reconstruct the full header keys and values.&lt;/p&gt;
&lt;img alt=&quot;HPACK: Header Compression for HTTP/2&quot; decoding=&quot;async&quot; height=&quot;150&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IYfczfC6ZCTxUVboaEZy.svg&quot; width=&quot;178&quot; /&gt;
&lt;p&gt;As one further optimization, the HPACK compression context consists of a static
and dynamic table: the static table is defined in the specification and
provides a list of common HTTP header fields that all connections are likely to
use (e.g., valid header names); the dynamic table is initially empty and is
updated based on exchanged values within a particular connection. As a result,
the size of each request is reduced by using static Huffman coding for values
that haven’t been seen before, and substitution of indexes for values that are
already present in the static or dynamic tables on each side.&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 definitions of the request and response header fields in HTTP/2 remains unchanged, with a few minor exceptions: all header field names are lowercase, and the request line is now split into individual &lt;code&gt;:method&lt;/code&gt;, &lt;code&gt;:scheme&lt;/code&gt;, &lt;code&gt;:authority&lt;/code&gt;, and &lt;code&gt;:path&lt;/code&gt; pseudo-header fields. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;security-and-performance-of-hpack&quot;&gt;Security and performance of HPACK &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#security-and-performance-of-hpack&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Early versions of HTTP/2 and SPDY used zlib, with a custom dictionary, to
compress all HTTP headers. This delivered an 85% to 88% reduction in the size
of the transferred header data, and a significant improvement in page load time
latency:&lt;/p&gt;
&lt;p&gt;On the lower-bandwidth DSL link, in which the upload link is only 375 Kbps,
request header compression in particular, led to significant page load time
improvements for certain sites (in other words, those that issued large number of
resource requests). We found a reduction of 45–1142 ms in page load time
simply due to header compression. &lt;a href=&quot;https://www.chromium.org/spdy/spdy-whitepaper&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;(SPDY whitepaper,
chromium.org)&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, in the summer of 2012, a &amp;quot;CRIME&amp;quot; security attack was published against
TLS and SPDY compression algorithms, which could result in session hijacking. As
a result, the zlib compression algorithm was replaced by HPACK, which was
specifically designed to: address the discovered security issues, be efficient
and simple to implement correctly, and of course, enable good compression of
HTTP header metadata.&lt;/p&gt;
&lt;p&gt;For full details of the HPACK compression algorithm, see
&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-httpbis-header-compression&quot; rel=&quot;noopener&quot;&gt;IETF HPACK - Header Compression for HTTP/2&lt;/a&gt;.&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/performance-http2/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hpbn.co/http2/&quot; rel=&quot;noopener&quot;&gt;“HTTP/2”&lt;/a&gt;
– The full article by Ilya Grigorik&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dassur.ma/things/h2setup/&quot; rel=&quot;noopener&quot;&gt;“Setting up HTTP/2”&lt;/a&gt;
– How to set up HTTP/2 in different backends by Surma&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1r7QXGYOLCh4fcUq0jDdDwKJWNqWK1o4xMtYpKZCJYjM/edit#slide=id.p19&quot; rel=&quot;noopener&quot;&gt;“HTTP/2 is here,
let’s optimize!”&lt;/a&gt;
– Presentation by Ilya Grigorik from Velocity 2015&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/edit&quot; rel=&quot;noopener&quot;&gt;“Rules of Thumb for HTTP/2 Push”&lt;/a&gt;
– An analysis by Tom Bergan, Simon Pelchat and Michael Buettner on when and how to use push.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-http2/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Surma</name>
    </author>
  </entry>
  
  <entry>
    <title>Delivering Fast and Light Applications with Save-Data</title>
    <link href="https://web.dev/optimizing-content-efficiency-save-data/"/>
    <updated>2016-02-18T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-save-data/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;https://httpwg.github.io/http-extensions/client-hints.html#the-save-data-hint&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Save-Data&lt;/code&gt; client hint request
header&lt;/a&gt;
available in Chrome, Opera, and Yandex browsers lets developers deliver lighter,
faster applications to users who opt-in to data saving mode in their browser.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-need-for-lightweight-pages&quot;&gt;The need for lightweight pages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#the-need-for-lightweight-pages&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;img alt=&quot;Weblight stats&quot; decoding=&quot;async&quot; height=&quot;423&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 600px) 600px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2dptWWpJQ5nE6Wf276UO.png?auto=format&amp;w=1200 1200w&quot; width=&quot;600&quot; /&gt;
&lt;p&gt;Everyone agrees that faster and lighter web pages provide a more satisfying user
experience, allow better content comprehension and retention, and deliver
increased conversions and revenue. &lt;a href=&quot;https://support.google.com/webmasters/answer/6211428&quot; rel=&quot;noopener&quot;&gt;Google
research&lt;/a&gt; has shown that
&amp;quot;…optimized pages load four times faster than the original page and use 80%
fewer bytes. Because these pages load so much faster, we also saw a 50% increase
in traffic to these pages.&amp;quot;&lt;/p&gt;
&lt;p&gt;And, although the number of 2G connections is &lt;a href=&quot;http://www.gsmamobileeconomy.com/GSMA_Global_Mobile_Economy_Report_2015.pdf&quot; rel=&quot;noopener&quot;&gt;finally on the
decline&lt;/a&gt;,
2G was &lt;a href=&quot;http://www.gsmamobileeconomy.com/GSMA_Global_Mobile_Economy_Report_2015.pdf&quot; rel=&quot;noopener&quot;&gt;still the dominant network
technology&lt;/a&gt;
in 2015. The penetration and availability of 3G and 4G networks is growing
rapidly, but the associated ownership costs and network constraints are still a
significant factor for hundreds of millions of users.&lt;/p&gt;
&lt;p&gt;These are strong arguments for page optimization.&lt;/p&gt;
&lt;p&gt;There are alternative methods for improving site speed without direct developer
involvement, such as proxy browsers and transcoding services. Although such
services are quite popular, they come with substantial drawbacks — simple
(and sometimes unacceptable) image and text compression, inability to process
secure (HTTPS) pages, only optimizing pages visited via a search result, and
more. The very popularity of these services is itself an indicator that web
developers are not properly addressing the high user demand for fast and light
applications and pages. But reaching that goal is a complex and sometimes
difficult path.&lt;/p&gt;
&lt;h2 id=&quot;the-save-data-request-header&quot;&gt;The &lt;code&gt;Save-Data&lt;/code&gt; request header &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#the-save-data-request-header&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One fairly straightforward technique is to let the browser help, using the
&lt;code&gt;Save-Data&lt;/code&gt; request header. By identifying this header, a web page can customize
and deliver an optimized user experience to cost- and performance-constrained
users.&lt;/p&gt;
&lt;p&gt;Supported browsers (below) allow the user to enable a *data saving- mode that
gives the browser permission to apply a set of optimizations to reduce the
amount of data required to render the page. When this feature is exposed, or
advertised, the browser may request lower resolution images, defer loading of
some resources, or route requests through a service that applies other
content-specific optimizations such as image and text resource compression.&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot;&gt;Browser support &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#browser-support&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome 49+&lt;/strong&gt; advertises &lt;code&gt;Save-Data&lt;/code&gt; &lt;a href=&quot;https://support.google.com/chrome/answer/2392284&quot; rel=&quot;noopener&quot;&gt;when the user
enables&lt;/a&gt; the &amp;quot;Data Saver&amp;quot;
option on mobile, or the &amp;quot;Data Saver&amp;quot; extension on desktop browsers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Opera 35+&lt;/strong&gt; advertises &lt;code&gt;Save-Data&lt;/code&gt; when the user enables &amp;quot;&lt;a href=&quot;http://www.opera.com/computer/features/fast-browser&quot; rel=&quot;noopener&quot;&gt;Opera
Turbo&lt;/a&gt;&amp;quot; mode on desktop,
or the &amp;quot;&lt;a href=&quot;http://www.opera.com/help/mobile/android#turbo&quot; rel=&quot;noopener&quot;&gt;Data savings&lt;/a&gt;&amp;quot; option
on Android browsers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yandex 16.2+&lt;/strong&gt; advertises &lt;code&gt;Save-Data&lt;/code&gt; when &lt;a href=&quot;https://yandex.com/support/newbrowser/search-and-browse/turbo.xml&quot; rel=&quot;noopener&quot;&gt;Turbo
mode&lt;/a&gt; is
enabled on desktop or &lt;a href=&quot;https://yandex.com/support/browser-mobile-android-phone/navigation/turbo-mode.xml&quot; rel=&quot;noopener&quot;&gt;mobile
browsers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;detecting-the-save-data-setting&quot;&gt;Detecting the &lt;code&gt;Save-Data&lt;/code&gt; setting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#detecting-the-save-data-setting&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To determine when to deliver the &amp;quot;light&amp;quot; experience to your users, your
application can check for the &lt;code&gt;Save-Data&lt;/code&gt; client hint request header. This
request header indicates the client&#39;s preference for reduced data usage due to
high transfer costs, slow connection speeds, or other reasons.&lt;/p&gt;
&lt;p&gt;When the user enables the data saving mode in their browser, the browser appends
the &lt;code&gt;Save-Data&lt;/code&gt; request header to all outgoing requests (both HTTP and HTTPS).
As of this writing, the browser only advertises one *&lt;em&gt;on&lt;/em&gt;- token in the header
(&lt;code&gt;Save-Data: on&lt;/code&gt;), but this may be extended in the future to indicate other user
preferences.&lt;/p&gt;
&lt;p&gt;Additionally, it&#39;s possible to detect if &lt;code&gt;Save-Data&lt;/code&gt; is turned on in JavaScript:&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 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;connection&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&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;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;saveData &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Implement data saving operations here.&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;Checking for the presence of the &lt;code&gt;connection&lt;/code&gt; object within the &lt;code&gt;navigator&lt;/code&gt;
object is vital, as it represents the Network Information API, which is only
implemented in Chrome, Chrome for Android, and Samsung Internet browsers. From
there, you only need to check if &lt;code&gt;navigator.connection.saveData&lt;/code&gt; is equal to
&lt;code&gt;true&lt;/code&gt;, and you can implement any data saving operations in that condition.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The Save-Data header revealed in Chrome&amp;#x27;s Developer Tools pictured along with the Data Saver extension.&quot; decoding=&quot;async&quot; height=&quot;623&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fvgG3HcmdSKyWutIkkJe.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Enabling the Data Saver extension in Chrome desktop.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If your application &lt;a href=&quot;https://web.dev/web/fundamentals/getting-started/push-notifications/step-03&quot;&gt;uses a service
worker&lt;/a&gt;, it can
inspect the request headers and apply relevant logic to optimize the experience.
Alternatively, the server can look for the advertised preferences in the
&lt;code&gt;Save-Data&lt;/code&gt; request header and return an alternate response — different
markup, smaller images and video, and so on.&lt;/p&gt;
&lt;p&gt;Tip: If you use &lt;a href=&quot;https://developers.google.com/speed/pagespeed/module/&quot; rel=&quot;noopener&quot;&gt;PageSpeed for Apache or Nginx&lt;/a&gt; to
optimize your pages, see &lt;a href=&quot;https://github.com/pagespeed/mod_pagespeed/issues/1258&quot; rel=&quot;noopener&quot;&gt;this
discussion&lt;/a&gt; to learn how
to enable &lt;code&gt;Save-Data&lt;/code&gt; savings for your users._&lt;/p&gt;
&lt;h2 id=&quot;implementation-tips-and-best-practices&quot;&gt;Implementation tips and best practices &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#implementation-tips-and-best-practices&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;When using &lt;code&gt;Save-Data&lt;/code&gt;, provide some UI devices that support it and allow users
to easily toggle between experiences. For example:
&lt;ul&gt;
&lt;li&gt;Notify users that &lt;code&gt;Save-Data&lt;/code&gt; is supported and encourage them to use it.&lt;/li&gt;
&lt;li&gt;Allow users to identify and choose the mode with appropriate prompts and
intuitive on/off buttons or checkboxes.&lt;/li&gt;
&lt;li&gt;When data saving mode is selected, announce and provide an easy and obvious
way to disable it and revert back to the full experience if desired.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remember that lightweight applications are not lesser applications. They don&#39;t
omit important functionality or data, they&#39;re just more cognizant of the
involved costs and the user experience. For example:
&lt;ul&gt;
&lt;li&gt;A photo gallery application may deliver lower resolution previews, or use a less
code-heavy carousel mechanism.&lt;/li&gt;
&lt;li&gt;A search application may return fewer results at a time, limit the number of
media-heavy results, or reduce the number of dependencies required to render
the page.&lt;/li&gt;
&lt;li&gt;A news-oriented site may show fewer stories, omit less popular categories,
or provide smaller media previews.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Provide server logic to check for the &lt;code&gt;Save-Data&lt;/code&gt; request header and consider
providing an alternate, lighter page response when it is enabled — e.g.,
reduce the number of required resources and dependencies, apply more aggressive
resource compression, etc.
&lt;ul&gt;
&lt;li&gt;If you&#39;re serving an alternate response based on the &lt;code&gt;Save-Data&lt;/code&gt; header,
remember to add it to the Vary list — &lt;code&gt;Vary: Save-Data&lt;/code&gt; — to tell
upstream caches that they should cache and serve this version only if the
&lt;code&gt;Save-Data&lt;/code&gt; request header is present. For more details, see the best practices
for
&lt;a href=&quot;https://httpwg.github.io/http-extensions/client-hints.html#interaction-with-caches&quot; rel=&quot;noopener&quot;&gt;interaction with caches&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you use a service worker, your application can detect when the data saving
option is enabled by checking for the presence of the &lt;code&gt;Save-Data&lt;/code&gt; request
header, or by checking the value of the &lt;code&gt;navigator.connection.saveData&lt;/code&gt;
property. If enabled, consider whether you can rewrite the request to fetch
fewer bytes, or use an already fetched response.&lt;/li&gt;
&lt;li&gt;Consider augmenting &lt;code&gt;Save-Data&lt;/code&gt; with other signals, such as information about
the user&#39;s connection type and technology (see &lt;a href=&quot;http://w3c.github.io/netinfo/#examples-of-usage&quot; rel=&quot;noopener&quot;&gt;NetInfo
API&lt;/a&gt;). For example, you might
want to serve the lightweight experience to any user on a 2G connection even if
&lt;code&gt;Save-Data&lt;/code&gt; is not enabled. Conversely, just because the user is on a &amp;quot;fast&amp;quot; 4G
connection doesn&#39;t mean they aren&#39;t interested in saving data — for
example, when roaming. Additionally, you could augment the presence of
&lt;code&gt;Save-Data&lt;/code&gt; with the &lt;code&gt;Device-Memory&lt;/code&gt; client hint to further adapt to users on
devices with limited memory. User device memory is also advertised in the
&lt;code&gt;navigator.deviceMemory&lt;/code&gt; client hint.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;recipes&quot;&gt;Recipes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#recipes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What you can achieve via &lt;code&gt;Save-Data&lt;/code&gt; is limited only to what you can come up
with. To give you an idea of what&#39;s possible, let&#39;s run through a couple of use
cases. You may come up with other use cases of your own as you read this, so
feel free to experiment and see what&#39;s possible!&lt;/p&gt;
&lt;h3 id=&quot;checking-for-save-data-in-server-side-code&quot;&gt;Checking for &lt;code&gt;Save-Data&lt;/code&gt; in server side code &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#checking-for-save-data-in-server-side-code&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While the &lt;code&gt;Save-Data&lt;/code&gt; state is something you &lt;em&gt;can&lt;/em&gt; detect in JavaScript via the
&lt;code&gt;navigator.connection.saveData&lt;/code&gt; property, detecting it on the server side is
sometimes preferable. JavaScript &lt;em&gt;can&lt;/em&gt; fail to execute in some cases. Plus,
server side detection is the only way to modify markup &lt;em&gt;before&lt;/em&gt; it&#39;s sent to the
client, which is involved in some of &lt;code&gt;Save-Data&lt;/code&gt;s most beneficial use cases.&lt;/p&gt;
&lt;p&gt;The specific syntax for detecting the &lt;code&gt;Save-Data&lt;/code&gt; header in server side code
depends on the language used, but the basic idea should be the same for any
application back end. In PHP, for example, request headers are stored in the
&lt;a href=&quot;http://php.net/manual/en/reserved.variables.server.php&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;$_SERVER&lt;/code&gt; superglobal
array&lt;/a&gt; at indexes
starting with &lt;code&gt;HTTP_&lt;/code&gt;. This means you can detect the &lt;code&gt;Save-Data&lt;/code&gt; header by
checking the existence and value of the &lt;code&gt;$_SERVER[&amp;quot;HTTP_SAVE_DATA&amp;quot;]&lt;/code&gt; variable
like so:&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;// false by default.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token variable&quot;&gt;$saveData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&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;// Check if the `Save-Data` header exists and is set to a value of &quot;on&quot;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;HTTP_SAVE_DATA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtolower&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;HTTP_SAVE_DATA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;on&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;// `Save-Data` detected!&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token variable&quot;&gt;$saveData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you place this check before any markup is sent to the client, the &lt;code&gt;$saveData&lt;/code&gt;
variable will contain the &lt;code&gt;Save-Data&lt;/code&gt; state, and will be available anywhere for
use on the page. With this mechanism illustrated, let&#39;s look a few examples of
how we can use it to limit how much data we send to the user.&lt;/p&gt;
&lt;h3 id=&quot;serve-low-resolution-images-for-high-resolution-screens&quot;&gt;Serve low resolution images for high resolution screens &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#serve-low-resolution-images-for-high-resolution-screens&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A common use case for images on the web involves serving images in sets of two:
One image for &amp;quot;standard&amp;quot; screens (1x), and another image that&#39;s twice as large
(2x) for high resolution screens (e.g., &lt;a href=&quot;https://en.wikipedia.org/wiki/Retina_Display&quot; rel=&quot;noopener&quot;&gt;Retina
Display&lt;/a&gt;). This class of high
resolution screens is not necessarily limited to high end devices, and is
becoming increasingly common. In cases where a lighter application experience is
preferred, it might be prudent to send lower resolution (1x) images to these
screens, rather than larger (2x) variants. To achieve this when the &lt;code&gt;Save-Data&lt;/code&gt;
header is present, we simply modify the markup we send to the client:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;if ($saveData === true) {&lt;br /&gt;  // Send a low-resolution version of the image for clients specifying `Save-Data`.&lt;br /&gt;  ?&gt;&lt;span class=&quot;token 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;butterfly-1x.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A butterfly perched on a flower.&lt;span class=&quot;token punctuation&quot;&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 php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;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;// Send the usual assets for everyone else.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;butterfly-1x.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;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;butterfly-2x.jpg 2x, butterfly-1x.jpg 1x&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 butterfly perched on a flower.&lt;span class=&quot;token punctuation&quot;&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 php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This use case is a perfect example of how little effort it takes to accommodate
someone who is specifically asking you to send them less data. If you don&#39;t like
modifying markup on the back end, you could also achieve the same result by
using a URL rewrite module such as &lt;a href=&quot;http://httpd.apache.org/docs/current/mod/mod_rewrite.html&quot; rel=&quot;noopener&quot;&gt;Apache&#39;s
&lt;code&gt;mod_rewrite&lt;/code&gt;&lt;/a&gt;. There
are &lt;a href=&quot;https://css-tricks.com/help-users-save-data/#article-header-id-0&quot; rel=&quot;noopener&quot;&gt;examples of how to achieve
this&lt;/a&gt; with
relatively little configuration.&lt;/p&gt;
&lt;p&gt;You could also extend this concept to CSS &lt;code&gt;background-image&lt;/code&gt; properties by
simply adding a class to the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element:&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 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 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;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&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 variable&quot;&gt;$saveData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;save-data&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;From here, you can target the &lt;code&gt;save-data&lt;/code&gt; class on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element in your
CSS to change how images are delivered. You could send low resolution background
images to high resolution screens as shown in the above HTML example, or omit
certain resources altogether.&lt;/p&gt;
&lt;h3 id=&quot;omit-non-essential-imagery&quot;&gt;Omit non-essential imagery &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#omit-non-essential-imagery&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some image content on the web is simply non-essential. While such imagery can
make for nice asides to content, they may not be desirable by those trying to
squeeze all they can out of metered data plans. In what is perhaps the simplest
use case of &lt;code&gt;Save-Data&lt;/code&gt;, we can use the PHP detection code from earlier and omit
non-essential image markup altogether:&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This paragraph is essential content. The image below may be humorous, but it&#39;s not critical to the content.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&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 variable&quot;&gt;$saveData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&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;// Only send this image if `Save-Data` hasn&#39;t been detected.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;meme.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;One does not simply consume data.&lt;span class=&quot;token punctuation&quot;&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 php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This technique can certainly have a pronounced effect, as you can see in the
figure below:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A comparison of non-critical imagery being loaded when Save-Data is absent, versus that same imagery being omitted when Save-Data is present.&quot; decoding=&quot;async&quot; height=&quot;330&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/fQ5ULmzstgJNbfV3tRTC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;A comparison of non-critical imagery being loaded when Save-Data is
absent, versus that same imagery being omitted when Save-Data is
present.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course, omitting images isn&#39;t the only possibility. You can also act on
&lt;code&gt;Save-Data&lt;/code&gt; to forego sending other non-critical resources, such as certain
typefaces.&lt;/p&gt;
&lt;h3 id=&quot;omit-non-essential-web-fonts&quot;&gt;Omit non-essential web fonts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#omit-non-essential-web-fonts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While web fonts don&#39;t usually make up nearly as much of a given page&#39;s total
payload as images often do, they&#39;re still quite popular. &lt;a href=&quot;https://httparchive.org/reports/page-weight#bytesFont&quot; rel=&quot;noopener&quot;&gt;They don&#39;t consume an
insignificant amount of
data&lt;/a&gt;, either.
Furthermore, the way browsers fetch and render fonts is more complicated than
you might think, with concepts such as
&lt;a href=&quot;https://www.zachleat.com/web/webfont-glossary/#foit&quot; rel=&quot;noopener&quot;&gt;FOIT&lt;/a&gt;,
&lt;a href=&quot;https://www.zachleat.com/web/webfont-glossary/#fout&quot; rel=&quot;noopener&quot;&gt;FOUT&lt;/a&gt;, and browser
heuristics making rendering a nuanced operation.&lt;/p&gt;
&lt;p&gt;It might stand to reason then that you might want to leave out non-essential web
fonts for users who want leaner user experiences. &lt;code&gt;Save-Data&lt;/code&gt; makes this a
reasonably painless thing to do.&lt;/p&gt;
&lt;p&gt;For example, let&#39;s say you&#39;ve included &lt;a href=&quot;https://fonts.google.com/specimen/Fira+Sans&quot; rel=&quot;noopener&quot;&gt;Fira
Sans&lt;/a&gt; from &lt;a href=&quot;https://fonts.google.com/&quot; rel=&quot;noopener&quot;&gt;Google
Fonts&lt;/a&gt; on your site. Fira Sans is an excellent body
copy font, but maybe it isn&#39;t so crucial to users trying to save data. By adding
a class of &lt;code&gt;save-data&lt;/code&gt; to the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element when the &lt;code&gt;Save-Data&lt;/code&gt; header is
present, we can write styles that invoke the non-essential typeface at first,
but then opts out of it when the &lt;code&gt;Save-Data&lt;/code&gt; header is present:&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;/* Opt into web fonts by default. */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;p,&lt;br /&gt;li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;Fira Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Arial&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Opt out of web fonts if the `save-Data` class is present. */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.save-data p,&lt;br /&gt;.save-data li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;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;Arial&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Using this approach, you can leave the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; snippet from Google Fonts in
place, because the browser speculatively loads CSS resources (including web
fonts) by first applying styles to the DOM, and then checking if any HTML
elements invoke any of the resources in the style sheet. If someone happens by
with &lt;code&gt;Save-Data&lt;/code&gt; on, Fira Sans will never load because the styled DOM never
invokes it. Arial will kick in, instead. It&#39;s not as nice as as Fira Sans, but
it may be preferable to those users trying to stretch their data plans.&lt;/p&gt;
&lt;h3 id=&quot;opting-out-of-server-pushes&quot;&gt;Opting out of server pushes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#opting-out-of-server-pushes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc7540#section-8.2&quot; rel=&quot;noopener&quot;&gt;HTTP/2 server push&lt;/a&gt; is often
the most touted feature of HTTP/2. &lt;a href=&quot;https://www.smashingmagazine.com/2017/04/guide-http2-server-push/#measuring-server-push-performance&quot; rel=&quot;noopener&quot;&gt;While it can boost
performance&lt;/a&gt;,
it can potentially be problematic due to &lt;a href=&quot;https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/&quot; rel=&quot;noopener&quot;&gt;caching
&amp;quot;gotchas&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re comfortable using server push and understand its current, quirky way
of interacting with the browser cache, then great. But you may want to consider
disabling it altogether if the &lt;code&gt;Save-Data&lt;/code&gt; header is present.&lt;/p&gt;
&lt;p&gt;Many HTTP/2 implementations kick off a server push for a resource when a &lt;code&gt;Link&lt;/code&gt;
response header invoking &lt;a href=&quot;https://www.w3.org/TR/preload/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rel=preload&lt;/code&gt;&lt;/a&gt; is set.
This leads to some confusion as to whether &lt;code&gt;rel=preload&lt;/code&gt; and server push are one
and the same, but they&#39;re two distinct things. &lt;code&gt;rel=preload&lt;/code&gt; is a resource hint,
and server push is part of HTTP/2. It just so happens the &lt;code&gt;Link&lt;/code&gt; header kicks
off a server push in a number of HTTP/2 implementations.&lt;/p&gt;
&lt;p&gt;The specification for &lt;code&gt;rel=preload&lt;/code&gt; &lt;a href=&quot;https://www.w3.org/TR/preload/#server-push-http-2&quot; rel=&quot;noopener&quot;&gt;addresses this potential pain
point&lt;/a&gt; by offering a &lt;code&gt;nopush&lt;/code&gt;
keyword to be used in &lt;code&gt;Link&lt;/code&gt; HTTP response headers. Using the back end
detection logic outlined earlier, you could append &lt;code&gt;nopush&lt;/code&gt; if &lt;code&gt;Save-Data&lt;/code&gt; is
present:&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;// `preload` like usual…&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token variable&quot;&gt;$preload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&amp;lt;/css/styles.css&gt;; rel=preload; as=style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$saveData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …but don&#39;t push anything if `Save-Data` is detected!&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token variable&quot;&gt;$preload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;; nopush&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Link: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$preload&lt;/span&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;&lt;a href=&quot;https://www.ctrl.blog/entry/http2-save-data-push&quot; rel=&quot;noopener&quot;&gt;There are other ways to achieve
this&lt;/a&gt;, some more more nuanced
than others, but the idea is the same: HTTP/2 server push is turned off when
&lt;code&gt;Save-Data&lt;/code&gt; is present.&lt;/p&gt;
&lt;p&gt;As you can see, there&#39;s a lot that can be accomplished with &lt;code&gt;Save-Data&lt;/code&gt;. These
are just a couple simple use cases to get you going, so feel free to experiment
and see what novel use cases you can come up with!&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-save-data/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Save-Data&lt;/code&gt; header does not have much nuance; it is either on or off, and
the application bears the burden of providing appropriate experiences based on
its setting, regardless of the reason.&lt;/p&gt;
&lt;p&gt;For example, some users might not allow data saving mode if they suspect there
will be a loss of app content or function, even in a poor connectivity
situation. Conversely, some users might enable it as a matter of course to keep
pages as small and simple as possible, even in a good connectivity situation.
It&#39;s best for your app to assume that the user wants the full and unlimited
experience until you have a clear indication otherwise via an explicit user
action.&lt;/p&gt;
&lt;p&gt;As site owners and web developers, let&#39;s take on the responsibility of managing
our content to improve the user experience for data- and cost-constrained users.&lt;/p&gt;
&lt;p&gt;For more detail on &lt;code&gt;Save-Data&lt;/code&gt; and excellent practical examples, see &lt;a href=&quot;https://css-tricks.com/help-users-save-data/&quot; rel=&quot;noopener&quot;&gt;Help Your
Users &lt;code&gt;Save Data&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Dave Gash</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Eliminate unnecessary downloads</title>
    <link href="https://web.dev/optimizing-content-efficiency-eliminate-downloads/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-eliminate-downloads/</id>
    <content type="html" mode="escaped">&lt;p&gt;The fastest and best-optimized resource is a resource not sent. You should eliminate unnecessary resources from your application. It&#39;s a good practice to question—and periodically revisit—the implicit and explicit assumptions with your team. Here are a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&#39;ve always included resource X on your pages, but does the cost of downloading and displaying it offset the value it delivers to the user? Can you measure and prove its value?&lt;/li&gt;
&lt;li&gt;Does the resource (especially if it&#39;s a third-party resource) deliver consistent performance? Is this resource in the critical path, or need to be? If the resource is in the critical path, could it be a single point of failure for the site? That is, if the resource is unavailable, does it affect performance and the user experience of your pages?&lt;/li&gt;
&lt;li&gt;Does this resource need or have an SLA? Does this resource follow performance best practices: compression, caching, and so on?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Too often, pages contain resources that are unnecessary, or worse, that hinder page performance without delivering much value to the visitor or to the site they&#39;re hosted on. This applies equally to first-party and third-party resources and widgets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Site A has decided to display a photo carousel on its homepage to allow the visitor to preview multiple photos with a quick click. All of the photos are loaded when the page is loaded, and the user advances through the photos.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Question:&lt;/strong&gt; Have you measured how many users view multiple photos in the carousel? You might be incurring high overhead by downloading resources that most visitors never view.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Site B has decided to install a third-party widget to display related content, improve social engagement, or provide some other service.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Question:&lt;/strong&gt; Have you tracked how many visitors use the widget or click-through on the content that the widget provides? Is the engagement that this widget generates enough to justify its overhead? Furthermore, is it feasible for you to use a loading strategy to ensure &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;the script isn&#39;t loaded until it&#39;s needed&lt;/a&gt;?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Determining whether to eliminate unnecessary downloads often requires a lot of careful thinking and measurement. For best results, periodically inventory and revisit these questions for every asset on your pages.&lt;/p&gt;
&lt;h2 id=&quot;effects-on-core-web-vitals&quot;&gt;Effects on Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-eliminate-downloads/#effects-on-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Core Web Vitals initative was introduced by Google to provide a set of metrics that reflect what users are experiencing as they use the web. While there are many optimization strategies for Core Web Vitals, questioning whether to load a particular resource on a page may light a path for you to improve these metrics on your website. Below are a few examples—grouped by each Core Web Vital—that are worth your consideration. Though this isn&#39;t an exhaustive list of examples (and there are many!), reading them over may give you food for thought.&lt;/p&gt;
&lt;h3 id=&quot;largest-contentful-paint-lcp&quot;&gt;Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-eliminate-downloads/#largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt; measures when the largest content (for example a hero image, or a headline) is loaded. It&#39;s considered an important perceptual metric that gives the user the impression that a site is loading quickly.&lt;/p&gt;
&lt;p&gt;In general, downloading less resources means that the bandwidth the user does have will be allocated across less resources, and may translate to an improvement in LCP. A classic example is that of lazy loading, where images outside of the viewport during page load will not be downloaded until the browser has determined the user is more likely to see them. If you have a large thumbnail gallery of, say, 50 images, lazy loading all but the top ten of them means that the browser can make more efficient use of the bandwidth available to it, and the first images the user will see will load more quickly.&lt;/p&gt;
&lt;p&gt;However, it&#39;s not just about loading less &lt;em&gt;images&lt;/em&gt;, necessarily. The browser has an internal prioritization scheme that determines how much bandwidth each resource should receive. However, even with this &lt;em&gt;all&lt;/em&gt; resources—particularly those downloaded at high priority—have the potential to deprive a potential LCP element&#39;s dependent resource. This is especially true on slow network connections. That dependent resource may be an image file that represents the page&#39;s LCP element, but it could also very well be a web font resource that the browser needs to render a text node that may be determined as the page&#39;s LCP element.&lt;/p&gt;
&lt;p&gt;If your website is heavy on text, it may be the case that a page&#39;s LCP element is a text node. While there are many &lt;a href=&quot;https://web.dev/font-best-practices/&quot;&gt;good font optimization and loading strategies&lt;/a&gt;, it may be worth considering whether a system font is sufficient for your website&#39;s needs, so that LCP elements which are text nodes can load without a dependency on a web font resource and paint almost immediately as the CSS and HTML arrives from the server.&lt;/p&gt;
&lt;h3 id=&quot;cumulative-layout-shift-cls&quot;&gt;Cumulative Layout Shift (CLS) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-eliminate-downloads/#cumulative-layout-shift-cls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every resource you load has the potential to contribute to a page&#39;s &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt;, particularly if has not finished downloading by the time of the initial paint. For images, avoid CLS involves practices such as setting explicit dimensions. For fonts, managing font loading and potentially fallback font matching can minimize shifts during a web font&#39;s swap period. For JavaScript, it could be managing how that script manipulates the DOM so that layout shifts are reduced to an acceptable amount.&lt;/p&gt;
&lt;p&gt;Every resource that contributes to a page&#39;s CLS requires some amount of work to ensure page layout is sufficiently stable. By questioning whether or not you need a specific resource, you&#39;re not just speeding up page loads, you&#39;re also reducing the cognitive effort necessary to preserve layout stability. That leads to not only a much less frustrating user experience, but a less frustrating developer experience, as you&#39;ll have more time to pursue other goals in your projects.&lt;/p&gt;
&lt;h3 id=&quot;interaction-to-next-paint-inp-and-first-input-delay-fid&quot;&gt;Interaction to Next Paint (INP) and First Input Delay (FID) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-eliminate-downloads/#interaction-to-next-paint-inp-and-first-input-delay-fid&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; are metrics that measure responsiveness to user inputs. &lt;a href=&quot;https://web.dev/inp-cwv/&quot;&gt;While INP is slated to replace FID as a Core Web Vital&lt;/a&gt; in March of 2024, optimization strategies for FID tend to also apply to INP. Furthermore, INP is generally more difficult to optimize for than FID, as it tracks the full interaction latency for &lt;em&gt;all&lt;/em&gt; page interactions, not just the input delay of the first interaction as FID measures.&lt;/p&gt;
&lt;p&gt;INP and FID tend to be most affected by JavaScript, as JavaScript is what drives most of the interactivity one experiences across the web. For both INP and FID, the amount of script resources downloaded during page load will kick off potentially expensive work involved in &lt;a href=&quot;https://web.dev/script-evaluation-and-long-tasks/&quot;&gt;script evaluation and compilation&lt;/a&gt;. The less JavaScript you load during startup, the less work the browser has to do at that critical point in the page experience.&lt;/p&gt;
&lt;p&gt;While there are strategies for reducing the &lt;em&gt;size&lt;/em&gt; of JavaScript resources downloaded during startup—such as code splitting and tree shaking—it&#39;s worth auditing the packages you use in your projects to see if they&#39;re necessary at all. For example, &lt;a href=&quot;https://lodash.com/&quot; rel=&quot;noopener&quot;&gt;lodash&lt;/a&gt; has many methods that are still useful today, but ships with methods that the browser provides out of the box, such as &lt;code&gt;Array&lt;/code&gt;-specific functions for &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot; rel=&quot;noopener&quot;&gt;mapping&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot; rel=&quot;noopener&quot;&gt;reducing&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot; rel=&quot;noopener&quot;&gt;filtering&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array&quot; rel=&quot;noopener&quot;&gt;many others&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Progressive enhancement is also &lt;a href=&quot;https://web.dev/adaptive-serving-based-on-network-quality/&quot;&gt;a useful approach&lt;/a&gt; to JavaScript, as it enables you to serve a baseline (but still functional) experience for users that you can add to for users with more powerful devices and faster network connections. Whether you adhere to the principle of progressive enhancement or not, the point remains: Every JavaScript resource you can avoid downloading can result in an experience that responds faster to user interactions, which is a vital aspect of web performance.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-eliminate-downloads/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Auditing your website for unnecessary downloads may be just one aspect of delivering fast user experiences, but it&#39;s one that has the potential for high impact. To recap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inventory your own assets and third-party assets on your pages.&lt;/li&gt;
&lt;li&gt;Measure the performance of each asset: its value and its technical performance.&lt;/li&gt;
&lt;li&gt;Determine if the resources are providing sufficient value.&lt;/li&gt;
&lt;li&gt;Understand the effect of unnecessary downloads on &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt; and supporting metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By optimizing content efficiency in this way, you&#39;re not only improving performance overall, you&#39;re also taking care not to waste users&#39; bandwidth, as well as potentially improving user-centric metrics and delivering a better user experience.&lt;/p&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Constructing the Object Model</title>
    <link href="https://web.dev/critical-rendering-path-constructing-the-object-model/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-constructing-the-object-model/</id>
    <content type="html" mode="escaped">&lt;p&gt;Before the browser can render the page, it needs to construct the DOM and
CSSOM trees. As a result, we need to ensure that we deliver both the HTML and
CSS to the browser as quickly as possible.&lt;/p&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Bytes → characters → tokens → nodes → object model.&lt;/li&gt;
&lt;li&gt;HTML markup is transformed into a Document Object Model (DOM); CSS markup is
transformed into a CSS Object Model (CSSOM).&lt;/li&gt;
&lt;li&gt;DOM and CSSOM are independent data structures.&lt;/li&gt;
&lt;li&gt;Chrome DevTools Performance panel allows us to capture and inspect the construction
and processing costs of DOM and CSSOM.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;document-object-model-dom&quot;&gt;Document Object Model (DOM) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/#document-object-model-dom&quot;&gt;#&lt;/a&gt;&lt;/h2&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;Critical Path&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/basic_dom.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s start with the simplest possible case: a plain HTML page with some text
and a single image. How does the browser process this page?&lt;/p&gt;
&lt;img alt=&quot;DOM construction process&quot; decoding=&quot;async&quot; height=&quot;443&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/cSL20piziX7XLekCPCuD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Conversion:&lt;/strong&gt; The browser reads the raw bytes of HTML off the disk or
network, and translates them to individual characters based on specified
encoding of the file (for example, UTF-8).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tokenizing:&lt;/strong&gt; The browser converts strings of characters into distinct
tokens—as specified by the &lt;a href=&quot;http://www.w3.org/TR/html5/&quot; rel=&quot;noopener&quot;&gt;W3C HTML5 standard&lt;/a&gt;
for example, &amp;quot;&amp;lt;html&amp;gt;&amp;quot;, &amp;quot;&amp;lt;body&amp;gt;&amp;quot;—and other strings within
angle brackets. Each token has a special meaning and its own set of rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lexing:&lt;/strong&gt; The emitted tokens are converted into &amp;quot;objects,&amp;quot; which define
their properties and rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM construction:&lt;/strong&gt; Finally, because the HTML markup defines relationships
between different tags (some tags are contained within other tags) the
created objects are linked in a tree data structure that also captures
the parent-child relationships defined in the original markup: the &lt;em&gt;HTML&lt;/em&gt;
object is a parent of the &lt;em&gt;body&lt;/em&gt; object, the &lt;em&gt;body&lt;/em&gt; is a parent of the
&lt;em&gt;paragraph&lt;/em&gt; object, and so on.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;DOM tree&quot; decoding=&quot;async&quot; height=&quot;299&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 582px) 582px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=1164 1164w&quot; width=&quot;582&quot; /&gt;
&lt;p&gt;&lt;strong&gt;The final output of this entire process is the Document Object Model (DOM)
of our simple page, which the browser uses for all further processing of the
page.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every time the browser processes HTML markup, it goes through all of the steps
above: convert bytes to characters, identify tokens, convert tokens to nodes,
and build the DOM tree. This entire process can take some time, especially if
we have a large amount of HTML to process.&lt;/p&gt;
&lt;img alt=&quot;Tracing DOM construction in DevTools&quot; decoding=&quot;async&quot; height=&quot;180&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 766px) 766px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/RHpJTxB4gBYuhzILaB7Y.png?auto=format&amp;w=1532 1532w&quot; width=&quot;766&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; We&#39;re assuming that you have basic familiarity with Chrome DevTools - that is, you know how to capture a network waterfall or record a timeline. If you need a quick refresher, check out the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/overview/&quot;&gt;Chrome DevTools documentation&lt;/a&gt;; if you&#39;re new to DevTools, check out &lt;a href=&quot;https://developer.chrome.com/docs/devtools/open/&quot;&gt;DevTools for Beginners&lt;/a&gt; in our DevTools documentation. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;If you open up Chrome DevTools and record a timeline while the page is loaded,
you can see the actual time taken to perform this step—in the example
above, it took us ~5ms to convert a chunk of HTML into a DOM tree. For a
larger page, this process could take significantly longer. When creating
smooth animations, this can easily become a bottleneck if the browser has to
process large amounts of HTML.&lt;/p&gt;
&lt;p&gt;The DOM tree captures the properties and relationships of the document markup,
but it doesn&#39;t tell us how the element will look when rendered. That’s the
responsibility of the CSSOM.&lt;/p&gt;
&lt;h2 id=&quot;css-object-model-cssom&quot;&gt;CSS Object Model (CSSOM) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/#css-object-model-cssom&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the browser was constructing the DOM of our simple page, it encountered
a link tag in the head section of the document referencing an external CSS
stylesheet: &lt;code&gt;style.css&lt;/code&gt;. Anticipating that it needs this resource to render the
page, it immediately dispatches a request for this resource, which comes back
with the following content:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;p span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 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 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;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We could have declared our styles directly within the HTML markup (inline), but
keeping our CSS independent of HTML allows us to treat content and design as
separate concerns: designers can work on CSS, developers can focus on HTML,
and so on.&lt;/p&gt;
&lt;p&gt;As with HTML, we need to convert the received CSS rules into something that
the browser can understand and work with. Hence, we repeat the HTML process,
but for CSS instead of HTML:&lt;/p&gt;
&lt;img alt=&quot;CSSOM construction steps&quot; decoding=&quot;async&quot; height=&quot;51&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yb5YfU0vx6vHvB7c0fyD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The CSS bytes are converted into characters, then tokens, then nodes, and
finally they are linked into a tree structure known as the &amp;quot;CSS Object Model&amp;quot;
(CSSOM):&lt;/p&gt;
&lt;img alt=&quot;CSSOM tree&quot; decoding=&quot;async&quot; height=&quot;299&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 582px) 582px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/keK3wDv9k2KzJA9QubFx.png?auto=format&amp;w=1164 1164w&quot; width=&quot;582&quot; /&gt;
&lt;p&gt;Why does the CSSOM have a tree structure? When computing the final set of
styles for any object on the page, the browser starts with the most general
rule applicable to that node (for example, if it is a child of a body element,
then all body styles apply) and then recursively refines the computed styles
by applying more specific rules; that is, the rules &amp;quot;cascade down.&amp;quot;&lt;/p&gt;
&lt;p&gt;To make it more concrete, consider the CSSOM tree above. Any text contained
within the &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tag that is placed within the body element, has a font
size of 16 pixels and has red text—the &lt;code&gt;font-size&lt;/code&gt; directive cascades
down from the &lt;code&gt;body&lt;/code&gt; to the &lt;code&gt;span&lt;/code&gt;. However, if a &lt;code&gt;span&lt;/code&gt; tag is child of a
paragraph (&lt;code&gt;p&lt;/code&gt;) tag, then its contents are not displayed.&lt;/p&gt;
&lt;p&gt;Also, note that the above tree is not the complete CSSOM tree and only shows
the styles we decided to override in our stylesheet. Every browser provides
a default set of styles also known as &amp;quot;user agent styles&amp;quot;—that’s what
we see when we don’t provide any of our own—and our styles simply
override these defaults.&lt;/p&gt;
&lt;p&gt;To find out how long the CSS processing takes you can record a timeline in
DevTools and look for &amp;quot;Recalculate Style&amp;quot; event: unlike DOM parsing, the
timeline doesn’t show a separate &amp;quot;Parse CSS&amp;quot; entry, and instead captures
parsing and CSSOM tree construction, plus the recursive calculation of
computed styles under this one event.&lt;/p&gt;
&lt;img alt=&quot;Tracing CSSOM construction in DevTools&quot; decoding=&quot;async&quot; height=&quot;180&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 766px) 766px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/nAI6iO8vsAf03EUs4nWZ.png?auto=format&amp;w=1532 1532w&quot; width=&quot;766&quot; /&gt;
&lt;p&gt;Our trivial stylesheet takes ~0.6ms to process and affects eight elements on
the page—not much, but once again, not free. However, where did the
eight elements come from? The CSSOM and DOM are independent data structures!
Turns out, the browser is hiding an important step. Next, lets talk about the
&lt;a href=&quot;https://web.dev/critical-rendering-path-render-tree-construction&quot;&gt;render tree&lt;/a&gt;
that links the DOM and CSSOM together.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Analyzing Critical Rendering Path Performance</title>
    <link href="https://web.dev/critical-rendering-path-analyzing-crp/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-analyzing-crp/</id>
    <content type="html" mode="escaped">&lt;p&gt;Identifying and resolving critical rendering path performance bottlenecks requires good knowledge of the common pitfalls. Let&#39;s take a hands-on tour and extract common performance patterns that will help you optimize your pages.&lt;/p&gt;
&lt;p&gt;Optimizing the critical rendering path allows the browser to paint the page as quickly as possible: faster pages translate into higher engagement, more pages viewed, and &lt;a href=&quot;https://www.google.com/think/multiscreen/success.html&quot; rel=&quot;noopener&quot;&gt;improved conversion&lt;/a&gt;. To minimize the amount of time a visitor spends viewing a blank screen, we need to optimize which resources are loaded and in which order.&lt;/p&gt;
&lt;p&gt;To help illustrate this process, let&#39;s start with the simplest possible case and incrementally build up our page to include additional resources, styles, and application logic. In the process, we&#39;ll optimize each case; we&#39;ll also see where things can go wrong.&lt;/p&gt;
&lt;p&gt;So far we&#39;ve focused exclusively on what happens in the browser after the resource (CSS, JS, or HTML file) is available to process. We&#39;ve ignored the time it takes to fetch the resource either from cache or from the network. We&#39;ll assume the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A network roundtrip (propagation latency) to the server costs 100ms.&lt;/li&gt;
&lt;li&gt;Server response time is 100ms for the HTML document and 10ms for all other files.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-hello-world-experience&quot;&gt;The hello world experience &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/#the-hello-world-experience&quot;&gt;#&lt;/a&gt;&lt;/h2&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&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;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Critical Path: No Style&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/basic_dom_nostyle.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ll start with basic HTML markup and a single image; no CSS or JavaScript. Let&#39;s open up our Network timeline in Chrome DevTools and inspect the resulting resource waterfall:&lt;/p&gt;
&lt;img alt=&quot;CRP&quot; decoding=&quot;async&quot; height=&quot;82&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.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; Although this doc uses DevTools to illustrate CRP concepts, DevTools is currently not well-suited for CRP analysis. See &lt;a href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/measure-crp#devtools&quot;&gt;What about DevTools?&lt;/a&gt; for more information. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;As expected, the HTML file took approximately 200ms to download. Note that the transparent portion of the blue line represents the length of time that the browser waits on the network without receiving any response bytes whereas the solid portion shows the time to finish the download after the first response bytes have been received. The HTML download is tiny (&amp;lt;4K), so all we need is a single roundtrip to fetch the full file. As a result, the HTML document takes approximately 200ms to fetch, with half the time spent waiting on the network and the other half waiting on the server response.&lt;/p&gt;
&lt;p&gt;When the HTML content becomes available, the browser parses the bytes, converts them into tokens, and builds the DOM tree. Notice that DevTools conveniently reports the time for the DOMContentLoaded event at the bottom (216ms), which also corresponds to the blue vertical line. The gap between the end of the HTML download and the blue vertical line (DOMContentLoaded) is the time it takes the browser to build the DOM tree—in this case, just a few milliseconds.&lt;/p&gt;
&lt;p&gt;Notice that our &amp;quot;awesome photo&amp;quot; did not block the &lt;code&gt;domContentLoaded&lt;/code&gt; event. Turns out, we can construct the render tree and even paint the page without waiting for each asset on the page: &lt;strong&gt;not all resources are critical to deliver the fast first paint&lt;/strong&gt;. In fact, when we talk about the critical rendering path we are typically talking about the HTML markup, CSS, and JavaScript. Images do not block the initial render of the page—although we should also try to get the images painted as soon as possible.&lt;/p&gt;
&lt;p&gt;That said, the &lt;code&gt;load&lt;/code&gt; event (also known as &lt;code&gt;onload&lt;/code&gt;), is blocked on the image: DevTools reports the &lt;code&gt;onload&lt;/code&gt; event at 335ms. Recall that the &lt;code&gt;onload&lt;/code&gt; event marks the point at which &lt;strong&gt;all resources&lt;/strong&gt; that the page requires have been downloaded and processed; at this point, the loading spinner can stop spinning in the browser (the red vertical line in the waterfall).&lt;/p&gt;
&lt;h2 id=&quot;adding-javascript-and-css-into-the-mix&quot;&gt;Adding JavaScript and CSS into the mix &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/#adding-javascript-and-css-into-the-mix&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our &amp;quot;Hello World experience&amp;quot; page seems simple but a lot goes on under the hood. In practice we&#39;ll need more than just the HTML: chances are, we&#39;ll have a CSS stylesheet and one or more scripts to add some interactivity to our page. Let&#39;s add both to the mix and see what happens:&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;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;span class=&quot;token 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;Critical Path: Measure Script&lt;span class=&quot;token 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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&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 function&quot;&gt;measureCRP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;timing.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/measure_crp_timing.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Before adding JavaScript and CSS:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM CRP&quot; decoding=&quot;async&quot; height=&quot;82&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Ymt4xfqjkmbXWcf0QpO1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;With JavaScript and CSS:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, JS&quot; decoding=&quot;async&quot; height=&quot;117&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Adding external CSS and JavaScript files adds two extra requests to our waterfall, all of which the browser dispatches at about the same time. However, &lt;strong&gt;note that there is now a much smaller timing difference between the &lt;code&gt;domContentLoaded&lt;/code&gt; and &lt;code&gt;onload&lt;/code&gt; events.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What happened?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unlike our plain HTML example, we also need to fetch and parse the CSS file to construct the CSSOM, and we need both the DOM and CSSOM to build the render tree.&lt;/li&gt;
&lt;li&gt;Because the page also contains a parser blocking JavaScript file, the &lt;code&gt;domContentLoaded&lt;/code&gt; event is blocked until the CSS file is downloaded and parsed: because the JavaScript might query the CSSOM, we must block the CSS file until it downloads before we can execute JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What if we replace our external script with an inline script?&lt;/strong&gt; Even if the script is inlined directly into the page, the browser can&#39;t execute it until the CSSOM is constructed. In short, inlined JavaScript is also parser blocking.&lt;/p&gt;
&lt;p&gt;That said, despite blocking on CSS, does inlining the script make the page render faster? Let&#39;s try it and see what happens.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;External JavaScript:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, JS&quot; decoding=&quot;async&quot; height=&quot;117&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;Inlined JavaScript:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, and inlined JS&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/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tz6KtBAhG51MAhMT3xFV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;We are making one less request, but both our &lt;code&gt;onload&lt;/code&gt; and &lt;code&gt;domContentLoaded&lt;/code&gt; times are effectively the same. Why? Well, we know that it doesn&#39;t matter if the JavaScript is inlined or external, because as soon as the browser hits the script tag it blocks and waits until the CSSOM is constructed. Further, in our first example, the browser downloads both CSS and JavaScript in parallel and they finish downloading at about the same time. In this instance, inlining the JavaScript code doesn&#39;t help us much. But there are several strategies that can make our page render faster.&lt;/p&gt;
&lt;p&gt;First, recall that all inline scripts are parser blocking, but for external scripts we can add the &amp;quot;async&amp;quot; keyword to unblock the parser. Let&#39;s undo our inlining and give that a try:&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;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;span class=&quot;token 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;Critical Path: Measure Async&lt;span class=&quot;token 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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&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 function&quot;&gt;measureCRP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;timing.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/measure_crp_async.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Parser-blocking (external) JavaScript:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, JS&quot; decoding=&quot;async&quot; height=&quot;117&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;Async (external) JavaScript:&lt;/em&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, async JS&quot; decoding=&quot;async&quot; height=&quot;122&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/FrwY2zgpS7Om2xvol89u.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Much better! The &lt;code&gt;domContentLoaded&lt;/code&gt; event fires shortly after the HTML is parsed; the browser knows not to block on JavaScript and since there are no other parser blocking scripts the CSSOM construction can also proceed in parallel.&lt;/p&gt;
&lt;p&gt;Alternatively, we could have inlined both the CSS and JavaScript:&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;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;span class=&quot;token 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;Critical Path: Measure Inlined&lt;span class=&quot;token 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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;      &lt;span class=&quot;token selector&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token selector&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token selector&quot;&gt;p span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 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 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;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;var&lt;/span&gt; span &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;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span&#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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;interactive&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change DOM text content&lt;/span&gt;&lt;br /&gt;      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;display &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;inline&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change CSSOM property&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// create a new element, style it, and append it to the DOM&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; loadTime &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;div&#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;      loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;You loaded this page on: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue&#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;loadTime&lt;span class=&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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/measure_crp_inlined.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, inline CSS, inline JS&quot; decoding=&quot;async&quot; height=&quot;80&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CMfwg0nJdKpr0uo1kXvn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Notice that the &lt;code&gt;domContentLoaded&lt;/code&gt; time is effectively the same as in the previous example; instead of marking our JavaScript as async, we&#39;ve inlined both the CSS and JS into the page itself. This makes our HTML page much larger, but the upside is that the browser doesn&#39;t have to wait to fetch any external resources; everything is right there in the page.&lt;/p&gt;
&lt;p&gt;As you can see, even with a very simple page, optimizing the critical rendering path is a non-trivial exercise: we need to understand the dependency graph between different resources, we need to identify which resources are &amp;quot;critical,&amp;quot; and we must choose among different strategies for how to include those resources on the page. There is no one solution to this problem; each page is different. You need to follow a similar process on your own to figure out the optimal strategy.&lt;/p&gt;
&lt;p&gt;That said, let&#39;s see if we can step back and identify some general performance patterns.&lt;/p&gt;
&lt;h2 id=&quot;performance-patterns&quot;&gt;Performance patterns &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/#performance-patterns&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest possible page consists of just the HTML markup; no CSS, no JavaScript, or other types of resources. To render this page the browser has to initiate the request, wait for the HTML document to arrive, parse it, build the DOM, and then finally render it on the screen:&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&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;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Critical Path: No Style&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/basic_dom_nostyle.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;img alt=&quot;Hello world CRP&quot; decoding=&quot;async&quot; height=&quot;171&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 617px) 617px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/CWG98NTczRE0lu8w5jBw.png?auto=format&amp;w=1234 1234w&quot; width=&quot;617&quot; /&gt;
&lt;p&gt;&lt;strong&gt;The time between T&lt;sub&gt;0&lt;/sub&gt; and T&lt;sub&gt;1&lt;/sub&gt; captures the network and server processing times.&lt;/strong&gt; In the best case (if the HTML file is small), just one network roundtrip fetches the entire document. Due to how the TCP transports protocols work, larger files may require more roundtrips. &lt;strong&gt;As a result, in the best case the above page has a one roundtrip (minimum) critical rendering path.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now, let&#39;s consider the same page but with an external CSS file:&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/analysis_with_css.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM + CSSOM CRP&quot; decoding=&quot;async&quot; height=&quot;199&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Once again, we incur a network roundtrip to fetch the HTML document, and then the retrieved markup tells us that we also need the CSS file; this means that the browser has to go back to the server and get the CSS before it can render the page on the screen. &lt;strong&gt;As a result, this page incurs a minimum of two roundtrips before it can be displayed.&lt;/strong&gt; Once again, the CSS file may take multiple roundtrips, hence the emphasis on &amp;quot;minimum&amp;quot;.&lt;/p&gt;
&lt;p&gt;Let&#39;s define the vocabulary we use to describe the critical rendering path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Critical Resource:&lt;/strong&gt; Resource that could block initial rendering of the page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Critical Path Length:&lt;/strong&gt; Number of roundtrips, or the total time required to fetch all of the critical resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Critical Bytes:&lt;/strong&gt; Total number of bytes required to get to first render of the page, which is the sum of the transfer filesizes of all critical resources.
Our first example, with a single HTML page, contained a single critical resource (the HTML document); the critical path length was also equal to one network roundtrip (assuming file was small), and the total critical bytes was just the transfer size of the HTML document itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let&#39;s compare that to the critical path characteristics of the HTML + CSS example above:&lt;/p&gt;
&lt;img alt=&quot;DOM + CSSOM CRP&quot; decoding=&quot;async&quot; height=&quot;199&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/KsgmVrOFWvTyTOydAbeP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; critical resources&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; or more roundtrips for the minimum critical path length&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;9&lt;/strong&gt; KB of critical bytes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We need both the HTML and CSS to construct the render tree. As a result, both HTML and CSS are critical resources: the CSS is fetched only after the browser gets the HTML document, hence the critical path length is at minimum two roundtrips. Both resources add up to a total of 9KB of critical bytes.&lt;/p&gt;
&lt;p&gt;Now let&#39;s add an extra JavaScript file into the mix.&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;app.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/analysis_with_css_js.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We added &lt;code&gt;app.js&lt;/code&gt;, which is both an external JavaScript asset on the page and a parser blocking (that is, critical) resource. Worse, in order to execute the JavaScript file we have to block and wait for CSSOM; recall that JavaScript can query the CSSOM and hence the browser pauses until &lt;code&gt;style.css&lt;/code&gt; is downloaded and CSSOM is constructed.&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, JavaScript CRP&quot; decoding=&quot;async&quot; height=&quot;117&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/TB6qP0gGOlo83Pb3qIQ4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;That said, in practice if we look at this page&#39;s &amp;quot;network waterfall,&amp;quot; you&#39;ll see that both the CSS and JavaScript requests are initiated at about the same time; the browser gets the HTML, discovers both resources, and initiates both requests. As a result, the above page has the following critical path characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;3&lt;/strong&gt; critical resources&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; or more roundtrips for the minimum critical path length&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;11&lt;/strong&gt; KB of critical bytes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We now have three critical resources that add up to 11KB of critical bytes, but our critical path length is still two roundtrips because we can transfer the CSS and JavaScript in parallel. &lt;strong&gt;Figuring out the characteristics of your critical rendering path means being able to identify the critical resources and also understanding how the browser will schedule their fetches.&lt;/strong&gt; Let&#39;s continue with our example.&lt;/p&gt;
&lt;p&gt;After chatting with our site developers, we realize that the JavaScript we included on our page doesn&#39;t need to be blocking; we have some analytics and other code in there that doesn&#39;t need to block the rendering of our page. With that knowledge, we can add the &amp;quot;async&amp;quot; attribute to the script tag to unblock the parser:&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;app.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/analysis_with_css_js_async.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, CSSOM, async JavaScript CRP&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/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/8rsf6hqutn9YbVKRLroK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;An asynchronous script has several advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The script is no longer parser blocking and is not part of the critical rendering path.&lt;/li&gt;
&lt;li&gt;Because there are no other critical scripts, the CSS doesn&#39;t need to block the &lt;code&gt;domContentLoaded&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;The sooner the &lt;code&gt;domContentLoaded&lt;/code&gt; event fires, the sooner other application logic can begin executing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result, our optimized page is now back to two critical resources (HTML and CSS), with a minimum critical path length of two roundtrips, and a total of 9KB of critical bytes.&lt;/p&gt;
&lt;p&gt;Finally, if the CSS stylesheet were only needed for print, how would that look?&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;print&lt;span class=&quot;token punctuation&quot;&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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;app.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/analysis_with_css_nb_js_async.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;img alt=&quot;DOM, non-blocking CSS, and async JavaScript CRP&quot; decoding=&quot;async&quot; height=&quot;273&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 796px) 796px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/k3OsnpbIYbBGaGTAHB8e.png?auto=format&amp;w=1592 1592w&quot; width=&quot;796&quot; /&gt;
&lt;p&gt;Because the style.css resource is only used for print, the browser doesn&#39;t need to block on it to render the page. Hence, as soon as DOM construction is complete, the browser has enough information to render the page. As a result, this page has only a single critical resource (the HTML document), and the minimum critical rendering path length is one roundtrip.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Measuring the Critical Rendering Path</title>
    <link href="https://web.dev/critical-rendering-path-measure-crp/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-measure-crp/</id>
    <content type="html" mode="escaped">&lt;p&gt;The foundation of every solid performance strategy is good measurement and
instrumentation. You can&#39;t optimize what you can&#39;t measure. This doc
explains different approaches for measuring CRP performance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Lighthouse approach runs a series of automated tests against a page,
and then generates a report on the page&#39;s CRP performance. This approach
provides a quick and easy high-level overview of CRP performance of a
particular page loaded in your browser, allowing you to rapidly test,
iterate, and improve its performance.&lt;/li&gt;
&lt;li&gt;The Navigation Timing API approach captures &lt;a href=&quot;https://en.wikipedia.org/wiki/Real_user_monitoring&quot; rel=&quot;noopener&quot;&gt;Real User
Monitoring (RUM)&lt;/a&gt;
metrics. As the name implies, these metrics are captured from real user
interactions with your site and provide an accurate view into
real-world CRP performance, as experienced by your users across a variety
of devices and network conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, a good approach is to use Lighthouse to identify obvious CRP
optimization opportunities, and then to instrument your code with the
Navigation Timing API to monitor how your app performs out in the wild.&lt;/p&gt;
&lt;h2 id=&quot;lighthouse&quot;&gt;Auditing a page with Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-measure-crp/#lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse is a web app auditing tool that runs a series of tests against a
given page, and then displays the page&#39;s results in a consolidated report. You
can run Lighthouse as a Chrome Extension or NPM module, which is
useful for integrating Lighthouse with continuous integration systems.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://web.dev/web/tools/lighthouse/&quot;&gt;Auditing Web Apps With Lighthouse&lt;/a&gt; to get started.&lt;/p&gt;
&lt;p&gt;When you run Lighthouse as a Chrome Extension, your page&#39;s CRP results look
like the screenshot below.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse&amp;#x27;s CRP audits&quot; decoding=&quot;async&quot; height=&quot;466&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 681px) 681px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/2qSS5tw7Ne5V8qwWqNnb.png?auto=format&amp;w=1362 1362w&quot; width=&quot;681&quot; /&gt;
&lt;p&gt;See &lt;a href=&quot;https://web.dev/web/tools/lighthouse/audits/critical-request-chains&quot;&gt;Critical Request Chains&lt;/a&gt; for more information on this audit&#39;s
results.&lt;/p&gt;
&lt;h2 id=&quot;navigation-timing&quot;&gt;Instrumenting your code with the Navigation Timing API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-measure-crp/#navigation-timing&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The combination of the Navigation Timing API and other browser events emitted
as the page loads allows you to capture and record the real-world CRP
performance of any page.&lt;/p&gt;
&lt;img alt=&quot;Navigation Timing&quot; decoding=&quot;async&quot; height=&quot;318&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 347px) 347px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZHMDYNtYGV3IwkTlRirS.png?auto=format&amp;w=694 694w&quot; width=&quot;347&quot; /&gt;
&lt;p&gt;Each of the labels in the above diagram corresponds to a high resolution timestamp that the browser tracks for each and every page it loads. In fact, in this specific case we&#39;re only showing a fraction of all the different timestamps — for now we&#39;re skipping all network related timestamps, but we&#39;ll come back to them in a future lesson.&lt;/p&gt;
&lt;p&gt;So, what do these timestamps mean?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;domLoading&lt;/code&gt;: this is the starting timestamp of the entire process, the
browser is about to start parsing the first received bytes of the HTML
document.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;domInteractive&lt;/code&gt;: marks the point when the browser has finished parsing all
of the HTML and DOM construction is complete.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;domContentLoaded&lt;/code&gt;: marks the point when both the DOM is ready and there are no stylesheets that are blocking JavaScript execution - meaning we can now (potentially) construct the render tree.
&lt;ul&gt;
&lt;li&gt;Many JavaScript frameworks wait for this event before they start executing their own logic. For this reason the browser captures the &lt;code&gt;EventStart&lt;/code&gt; and &lt;code&gt;EventEnd&lt;/code&gt; timestamps to allow us to track how long this execution took.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;domComplete&lt;/code&gt;: as the name implies, all of the processing is complete and
all of the resources on the page (images, etc.) have finished downloading -
in other words, the loading spinner has stopped spinning.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loadEvent&lt;/code&gt;: as a final step in every page load the browser fires an
&lt;code&gt;onload&lt;/code&gt; event which can trigger additional application logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The HTML specification dictates specific conditions for each and every event: when it should be fired, which conditions should be met, and so on. For our purposes, we&#39;ll focus on a few key milestones related to the critical rendering path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;domInteractive&lt;/code&gt; marks when DOM is ready.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;domContentLoaded&lt;/code&gt; typically marks when &lt;a href=&quot;http://calendar.perfplanet.com/2012/deciphering-the-critical-rendering-path/&quot; rel=&quot;noopener&quot;&gt;both the DOM and CSSOM are ready&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;If there is no parser blocking JavaScript then &lt;code&gt;DOMContentLoaded&lt;/code&gt; will fire immediately after &lt;code&gt;domInteractive&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;domComplete&lt;/code&gt; marks when the page and all of its subresources are ready.&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 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;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;span class=&quot;token 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;Critical Path: Measure&lt;span class=&quot;token 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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;measureCRP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&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; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;performance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timing&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          interactive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domInteractive &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domLoading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          dcl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domContentLoadedEventStart &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domLoading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          complete &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domComplete &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domLoading&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; stats &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;p&#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;        stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&#39;interactive: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          interactive &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&#39;ms, &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&#39;dcl: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          dcl &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&#39;ms, complete: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          complete &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&#39;ms&#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;stats&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token 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;body&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 function&quot;&gt;measureCRP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/measure_crp.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The above example may seem a little daunting on first sight, but in reality it is actually pretty simple. The Navigation Timing API captures all the relevant timestamps and our code simply waits for the &lt;code&gt;onload&lt;/code&gt; event to fire — recall that &lt;code&gt;onload&lt;/code&gt; event fires after &lt;code&gt;domInteractive&lt;/code&gt;, &lt;code&gt;domContentLoaded&lt;/code&gt; and &lt;code&gt;domComplete&lt;/code&gt; — and computes the difference between the various timestamps.&lt;/p&gt;
&lt;img alt=&quot;NavTiming demo&quot; decoding=&quot;async&quot; height=&quot;370&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 717px) 717px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/tu3s8ythdotqqoxQDoEd.png?auto=format&amp;w=1434 1434w&quot; width=&quot;717&quot; /&gt;
&lt;p&gt;All said and done, we now have some specific milestones to track and a simple function to output these measurements. Note that instead of printing these metrics on the page you can also modify the code to send these metrics to an analytics server (&lt;a href=&quot;https://support.google.com/analytics/answer/1205784&quot; rel=&quot;noopener&quot;&gt;Google Analytics does this automatically&lt;/a&gt;), which is a great way to keep tabs on performance of your pages and identify candidate pages that can benefit from some optimization work.&lt;/p&gt;
&lt;h2 id=&quot;devtools&quot;&gt;What about DevTools? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-measure-crp/#devtools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although these docs sometimes use the Chrome DevTools Network panel to
illustrate CRP concepts, DevTools is currently not well-suited for CRP
measurements because it does not have a built-in mechanism for isolating
critical resources. Run a &lt;a href=&quot;https://web.dev/critical-rendering-path-measure-crp/#lighthouse&quot;&gt;Lighthouse&lt;/a&gt; audit to help
identify such resources.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-measure-crp/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimizing the Critical Rendering Path</title>
    <link href="https://web.dev/critical-rendering-path-optimizing-critical-rendering-path/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-optimizing-critical-rendering-path/</id>
    <content type="html" mode="escaped">&lt;p&gt;To deliver the fastest possible time to first render, we need
to minimize three variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The number of critical resources.&lt;/li&gt;
&lt;li&gt;The critical path length.&lt;/li&gt;
&lt;li&gt;The number of critical bytes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A critical resource is a resource that could block initial rendering of the page. The fewer of these resources, the less work for the browser, the CPU, and other resources.&lt;/p&gt;
&lt;p&gt;Similarly, the critical path length is a function of the dependency graph between the critical resources and their bytesize: some resource downloads can only be initiated after a previous resource has been processed, and the larger the resource the more roundtrips it takes to download.&lt;/p&gt;
&lt;p&gt;Finally, the fewer critical bytes the browser has to download, the faster it can process content and render it visible on the screen. To reduce the number of bytes, we can reduce the number of resources (eliminate them or make them non-critical) and ensure that we minimize the transfer size by compressing and optimizing each resource.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The general sequence of steps to optimize the critical rendering path is:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Analyze and characterize your critical path: number of resources, bytes, length.&lt;/li&gt;
&lt;li&gt;Minimize number of critical resources: eliminate them, defer their download, mark them as async, and so on.&lt;/li&gt;
&lt;li&gt;Optimize the number of critical bytes to reduce the download time (number of roundtrips).&lt;/li&gt;
&lt;li&gt;Optimize the order in which the remaining critical resources are loaded: download all critical assets as early as possible to shorten the critical path length.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-optimizing-critical-rendering-path/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Render Blocking CSS</title>
    <link href="https://web.dev/critical-rendering-path-render-blocking-css/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-render-blocking-css/</id>
    <content type="html" mode="escaped">&lt;p&gt;By default, CSS is treated as a render blocking resource, which means that the
browser won&#39;t render any processed content until the CSSOM is
constructed. Make sure to keep your CSS lean, deliver it as quickly as
possible, and use media types and queries to unblock rendering.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://web.dev/critical-rendering-path-render-tree-construction/&quot;&gt;render tree construction&lt;/a&gt; we saw that the critical rendering path requires both the DOM and the CSSOM to construct the render tree. This creates an important performance implication: &lt;strong&gt;both HTML and CSS are render blocking resources.&lt;/strong&gt; The HTML is obvious, since without the DOM we would not have anything to render, but the CSS requirement may be less obvious. What would happen if we try to render a typical page without blocking rendering on CSS?&lt;/p&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-render-blocking-css/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;By default, CSS is treated as a render blocking resource.&lt;/li&gt;
&lt;li&gt;Media types and media queries allow us to mark some CSS resources as non-render blocking.&lt;/li&gt;
&lt;li&gt;The browser downloads all CSS resources, regardless of blocking or non-blocking behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;switcher&quot;&gt;
&lt;figure&gt;
  &lt;img alt=&quot;NYTimes with CSS&quot; decoding=&quot;async&quot; height=&quot;552&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 300px) 300px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/c3ZTThABrj7JQu5Xajaf.png?auto=format&amp;w=600 600w&quot; width=&quot;300&quot; /&gt;
  &lt;figcaption&gt;The New York Times with CSS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;NYTimes without CSS&quot; decoding=&quot;async&quot; height=&quot;552&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 300px) 300px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/PYuJaMw0VGOq4im1LsCO.png?auto=format&amp;w=600 600w&quot; width=&quot;300&quot; /&gt;
  &lt;figcaption&gt;The New York Times without CSS (FOUC)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;The above example, showing the NYTimes website with and without CSS, demonstrates why rendering is blocked until CSS is available---without CSS the page is relatively unusable. The experience on the right is often referred to as a &amp;quot;Flash of Unstyled Content&amp;quot; (FOUC). The browser blocks rendering until it has both the DOM and the CSSOM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;CSS is a render blocking resource. Get it to the client as soon and as quickly as possible to optimize the time to first render.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, what if we have some CSS styles that are only used under certain conditions, for example, when the page is being printed or being projected onto a large monitor? It would be nice if we didn’t have to block rendering on these resources.&lt;/p&gt;
&lt;p&gt;CSS &amp;quot;media types&amp;quot; and &amp;quot;media queries&amp;quot; allow us to address these use cases:&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;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;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;print.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;print&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;other.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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: 40em)&lt;span class=&quot;token punctuation&quot;&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;A &lt;a href=&quot;https://web.dev/design-and-ux/responsive/#use-css-media-queries-for-responsiveness&quot;&gt;media query&lt;/a&gt; consists of a media type and zero or more expressions that check for the conditions of particular media features. For example, our first stylesheet declaration doesn&#39;t provide a media type or query, so it applies in all cases; that is to say, it is always render blocking. On the other hand, the second stylesheet declaration applies only when the content is being printed---perhaps you want to rearrange the layout, change the fonts, and so on, and hence this stylesheet declaration doesn&#39;t need to block the rendering of the page when it is first loaded. Finally, the last stylesheet declaration provides a &amp;quot;media query,&amp;quot; which is executed by the browser: if the conditions match, the browser blocks rendering until the style sheet is downloaded and processed.&lt;/p&gt;
&lt;p&gt;By using media queries, we can tailor our presentation to specific use cases, such as display versus print, and also to dynamic conditions such as changes in screen orientation, resize events, and more. &lt;strong&gt;When declaring your style sheet assets, pay close attention to the media type and queries; they greatly impact critical rendering path performance.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s consider some hands-on examples:&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;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;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;all&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;portrait.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;orientation:portrait&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;print.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;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;print&lt;span class=&quot;token punctuation&quot;&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;ul&gt;
&lt;li&gt;The first declaration is render blocking and matches in all conditions.&lt;/li&gt;
&lt;li&gt;The second declaration is also render blocking: &amp;quot;all&amp;quot; is the default type so if you don’t specify any type, it’s implicitly set to &amp;quot;all&amp;quot;. Hence, the first and second declarations are actually equivalent.&lt;/li&gt;
&lt;li&gt;The third declaration has a dynamic media query, which is evaluated when the page is loaded. Depending on the orientation of the device while the page is loading, portrait.css may or may not be render blocking.&lt;/li&gt;
&lt;li&gt;The last declaration is only applied when the page is being printed so it is not render blocking when the page is first loaded in the browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, note that &amp;quot;render blocking&amp;quot; only refers to whether the browser has to hold the initial rendering of the page on that resource. In either case, the browser still downloads the CSS asset, albeit with a lower priority for non-blocking resources.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-render-blocking-css/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Render-tree Construction, Layout, and Paint</title>
    <link href="https://web.dev/critical-rendering-path-render-tree-construction/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-render-tree-construction/</id>
    <content type="html" mode="escaped">&lt;p&gt;The CSSOM and DOM trees are combined into a render tree, which is then used
to compute the layout of each visible element and serves as an input to the
paint process that renders the pixels to screen. Optimizing each of these
steps is critical to achieving optimal rendering performance.&lt;/p&gt;
&lt;p&gt;In the previous section on constructing the object model, we built the DOM and
the CSSOM trees based on the HTML and CSS input. However, both of these are
independent objects that capture different aspects of the document: one
describes the content, and the other describes the style rules that need to be
applied to the document. How do we merge the two and get the browser to render
pixels on the screen?&lt;/p&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-render-tree-construction/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The DOM and CSSOM trees combine to form the render tree.&lt;/li&gt;
&lt;li&gt;Render tree contains only the nodes required to render the page.&lt;/li&gt;
&lt;li&gt;Layout computes the exact position and size of each object.&lt;/li&gt;
&lt;li&gt;The last step is paint, which takes in the final render tree and renders the pixels to the screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, the browser combines the DOM and CSSOM into a &amp;quot;render tree,&amp;quot; which captures all the visible DOM content on the page and all the CSSOM style information for each node.&lt;/p&gt;
&lt;img alt=&quot;DOM and CSSOM are combined to create the render tree&quot; decoding=&quot;async&quot; height=&quot;374&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/b6Z2Gu6UD1x1imOu1tJV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To construct the render tree, the browser roughly does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Starting at the root of the DOM tree, traverse each visible node.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some nodes are not visible (for example, script tags, meta tags, and so on), and are omitted since they are not reflected in the rendered output.&lt;/li&gt;
&lt;li&gt;Some nodes are hidden via CSS and are also omitted from the render tree; for example, the span node---in the example above---is missing from the render tree because we have an explicit rule that sets the &amp;quot;display: none&amp;quot; property on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each visible node, find the appropriate matching CSSOM rules and apply them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Emit visible nodes with content and their computed styles.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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 a brief aside, note that &lt;code&gt;visibility: hidden&lt;/code&gt; is different from &lt;code&gt;display: none&lt;/code&gt;. The former makes the element invisible, but the element still occupies space in the layout (that is, it&#39;s rendered as an empty box), whereas the latter (&lt;code&gt;display: none&lt;/code&gt;) removes the element entirely from the render tree such that the element is invisible and is not part of the layout. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The final output is a render tree that contains both the content and style information of all the visible content on the screen. &lt;strong&gt;With the render tree in place, we can proceed to the &amp;quot;layout&amp;quot; stage.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Up to this point we&#39;ve calculated which nodes should be visible and their computed styles, but we have not calculated their exact position and size within the &lt;a href=&quot;https://web.dev/web/fundamentals/design-and-ux/responsive/#set-the-viewport&quot;&gt;viewport&lt;/a&gt; of the device---that&#39;s the &amp;quot;layout&amp;quot; stage, also known as &amp;quot;reflow.&amp;quot;&lt;/p&gt;
&lt;p&gt;To figure out the exact size and position of each object on the page, the browser begins at the root of the render tree and traverses it. Let&#39;s consider a simple, hands-on example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token 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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&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;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Critial Path: Hello world!&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token 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; 50%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token 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; 50%&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;Hello world!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/nested.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The body of the above page contains two nested div&#39;s: the first (parent) div sets the display size of the node to 50% of the viewport width, and the second div---contained by the parent---sets its width to be 50% of its parent; that is, 25% of the viewport width.&lt;/p&gt;
&lt;img alt=&quot;Calculating layout information&quot; decoding=&quot;async&quot; height=&quot;281&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 616px) 616px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/IIr281DuPwRi9fiXhNg4.png?auto=format&amp;w=1232 1232w&quot; width=&quot;616&quot; /&gt;
&lt;p&gt;The output of the layout process is a &amp;quot;box model,&amp;quot; which precisely captures the exact position and size of each element within the viewport: all of the relative measurements are converted to absolute pixels on the screen.&lt;/p&gt;
&lt;p&gt;Finally, now that we know which nodes are visible, and their computed styles and geometry, we can pass this information to the final stage, which converts each node in the render tree to actual pixels on the screen. This step is often referred to as &amp;quot;painting&amp;quot; or &amp;quot;rasterizing.&amp;quot;&lt;/p&gt;
&lt;p&gt;This can take some time because the browser has to do quite a bit of work. However, Chrome DevTools can provide some insight into all three of the stages described above. Let&#39;s examine the layout stage for our original &amp;quot;hello world&amp;quot; example:&lt;/p&gt;
&lt;img alt=&quot;Measuring layout in DevTools&quot; decoding=&quot;async&quot; height=&quot;180&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 766px) 766px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OHEypUdtsMQ9raPnW116.png?auto=format&amp;w=1532 1532w&quot; width=&quot;766&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;quot;Layout&amp;quot; event captures the render tree construction, position, and size calculation in the Timeline.&lt;/li&gt;
&lt;li&gt;When layout is complete, the browser issues &amp;quot;Paint Setup&amp;quot; and &amp;quot;Paint&amp;quot; events, which convert the render tree to pixels on the screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The time required to perform render tree construction, layout and paint varies based on the size of the document, the applied styles, and the device it is running on: the larger the document, the more work the browser has; the more complicated the styles, the more time taken for painting also (for example, a solid color is &amp;quot;cheap&amp;quot; to paint, while a drop shadow is &amp;quot;expensive&amp;quot; to compute and render).&lt;/p&gt;
&lt;p&gt;The page is finally visible in the viewport:&lt;/p&gt;
&lt;img alt=&quot;Rendered Hello World page&quot; decoding=&quot;async&quot; height=&quot;370&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 717px) 717px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/H9mc9hE33imsdh7TfCgm.png?auto=format&amp;w=1434 1434w&quot; width=&quot;717&quot; /&gt;
&lt;p&gt;Here&#39;s a quick recap of the browser&#39;s steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Process HTML markup and build the DOM tree.&lt;/li&gt;
&lt;li&gt;Process CSS markup and build the CSSOM tree.&lt;/li&gt;
&lt;li&gt;Combine the DOM and CSSOM into a render tree.&lt;/li&gt;
&lt;li&gt;Run layout on the render tree to compute geometry of each node.&lt;/li&gt;
&lt;li&gt;Paint the individual nodes to the screen.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our demo page may look simple, but it requires quite a bit of work. If either the DOM or CSSOM were modified, you would have to repeat the process in order to figure out which pixels would need to be re-rendered on the screen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Optimizing the critical rendering path&lt;/em&gt; is the process of minimizing the total amount of time spent performing steps 1 through 5 in the above sequence.&lt;/strong&gt; Doing so renders content to the screen as quickly as possible and also reduces the amount of time between screen updates after the initial render; that is, achieve higher refresh rates for interactive content.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-render-tree-construction/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Critical Rendering Path</title>
    <link href="https://web.dev/critical-rendering-path/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;em&gt;Optimizing the critical rendering path&lt;/em&gt; refers to prioritizing the display of
content that relates to the current user action.&lt;/p&gt;
&lt;p&gt;Delivering a fast web experience requires a lot of work by the browser. Most of
this work is hidden from us as web developers: we write the markup, and a nice
looking page comes out on the screen. But how exactly does the browser go from
consuming our HTML, CSS, and JavaScript to rendered pixels on the screen?&lt;/p&gt;
&lt;p&gt;Optimizing for performance is all about understanding what happens in these
intermediate steps between receiving the HTML, CSS, and JavaScript bytes and
the required processing to turn them into rendered pixels - that&#39;s
the &lt;strong&gt;critical rendering path&lt;/strong&gt;.&lt;/p&gt;
&lt;img alt=&quot;progressive page rendering&quot; decoding=&quot;async&quot; height=&quot;300&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 611px) 611px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/yIiIUEYItai4zX07ZJda.png?auto=format&amp;w=1222 1222w&quot; width=&quot;611&quot; /&gt;
&lt;p&gt;By optimizing the critical rendering path we can significantly improve the
time to first render of our pages. Further, understanding the critical
rendering path also serves as a foundation for building well-performing
interactive applications. The interactive updates process is the same, just done in a continuous loop and ideally at 60 frames per second!
But first, an overview of how the browser displays a simple page.&lt;/p&gt;
&lt;h2 id=&quot;critical-rendering-path&quot;&gt;Critical Rendering Path &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path/#critical-rendering-path&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You will learn how to optimize any website for speed by diving into the details of how mobile and desktop browsers render pages.
You’ll learn about the Critical Rendering Path, or the set of steps browsers must take to convert HTML, CSS and JavaScript into living,
breathing websites. From there, you’ll start exploring and experimenting with tools to measure performance and simple strategies to deliver the first
pixels to the screen as early as possible. You’ll learn how to dive into recommendations from PageSpeed Insights and the Timeline view of Google Chrome’s Developer
Tools to find the data you need to achieve immediate performance boosts!&lt;/p&gt;
&lt;p&gt;This is a free course offered through &lt;a href=&quot;https://www.udacity.com/course/website-performance-optimization--ud884&quot; rel=&quot;noopener&quot;&gt;Udacity&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path/#additional-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-constructing-the-object-model/&quot;&gt;Constructing the Object Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-render-tree-construction/&quot;&gt;Render-tree Construction, Layout, and Paint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-render-blocking-css/&quot;&gt;Render Blocking CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-measure-crp/&quot;&gt;Measuring the Critical Rendering Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-analyzing-crp/&quot;&gt;Analyzing Critical Rendering Path Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-optimizing-critical-rendering-path/&quot;&gt;Optimizing the Critical Rendering Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-page-speed-rules-and-recommendations/&quot;&gt;PageSpeed Rules and Recommendations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimizing Encoding and Transfer Size of Text-Based Assets</title>
    <link href="https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/</id>
    <content type="html" mode="escaped">&lt;p&gt;Next to eliminating unnecessary resource downloads, the best thing you can do to
improve page-load speed is to minimize the overall download size by optimizing and
compressing the remaining resources.&lt;/p&gt;
&lt;h2 id=&quot;data-compression-101&quot;&gt;Data compression 101 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#data-compression-101&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After you’ve eliminated any unnecessary resources, the next step is to compress
the remaining resources that the browser has to download. Depending on the resource
type—text, images, fonts, and so on—there are many different techniques
to choose from: generic tools that can be enabled on the server, pre-processing
optimizations for specific content types, and resource-specific optimizations that
require input from the developer.&lt;/p&gt;
&lt;p&gt;Delivering the best performance requires a combination of all of these techniques.&lt;/p&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compression is the process of encoding information using fewer bits.&lt;/li&gt;
&lt;li&gt;Eliminating unnecessary data always yields the best results.&lt;/li&gt;
&lt;li&gt;There are many different compression techniques and algorithms.&lt;/li&gt;
&lt;li&gt;You will need a variety of techniques to achieve the best compression.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The process of reducing the size of data is &lt;em&gt;data compression&lt;/em&gt;. Many people have
contributed algorithms, techniques, and optimizations to improve compression ratios,
speed, and memory requirements of various compressors. A full discussion of data
compression is beyond the scope of this topic. However, it&#39;s important to understand,
at a high level, how compression works and the techniques you can use to reduce
the size of various assets that your pages require.&lt;/p&gt;
&lt;p&gt;To illustrate the core principles of these techniques, consider the process of
optimizing a simple text message format that was invented just for this example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;    # Below is a secret message, which consists of a set of headers in&lt;br /&gt;    # key-value format followed by a newline and the encrypted message.&lt;br /&gt;    format: secret-cipher&lt;br /&gt;    date: 08/25/16&lt;br /&gt;    AAAZZBBBBEEEMMM EEETTTAAA&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Messages may contain arbitrary annotations, which are indicated by the &amp;quot;#&amp;quot; prefix.
Annotations do not affect the meaning or any other behavior of the message.&lt;/li&gt;
&lt;li&gt;Messages may contain &lt;em&gt;headers&lt;/em&gt;, which are key-value pairs (separated by &amp;quot;:&amp;quot;)
that appear at the beginning of the message.&lt;/li&gt;
&lt;li&gt;Messages carry text payloads.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What can you do to reduce the size of the above message, which is currently
200 characters?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The comment is interesting, but it doesn’t actually affect the meaning of the message.
Eliminate it when transmitting the message.&lt;/li&gt;
&lt;li&gt;There are good techniques to encode headers in an efficient manner. For example,
if you know that all messages have &amp;quot;format&amp;quot; and &amp;quot;date,&amp;quot; you could convert those
to short integer IDs and just send those. However, that might not be true, so just
leave it alone for now.&lt;/li&gt;
&lt;li&gt;The payload is text only, and while we don’t know what the contents of it really are
(apparently, it’s using a &amp;quot;secret-message&amp;quot;), just looking at the text shows that
there&#39;s a lot of redundancy in it. Perhaps instead of sending repeated letters,
you can just count the number of repeated letters and encode them more efficiently.
For example, &amp;quot;AAA&amp;quot; becomes &amp;quot;3A&amp;quot;, which represents a sequence of three A’s.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Combining these techniques produces the following result:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;    format: secret-cipher&lt;br /&gt;    date: 08/25/16&lt;br /&gt;    3A2Z4B3E3M 3E3T3A&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The new message is 56 characters long, which means that you&#39;ve compressed the original
message by an impressive 72%.&lt;/p&gt;
&lt;p&gt;This is all great, but how does this help us optimize our web pages? We’re not going
to try to invent our compression algorithms, but, as you will see, we can use the
exact same techniques and thought processes when optimizing various resources on
our pages: preprocessing, context-specific optimizations, and different algorithms
for different content.&lt;/p&gt;
&lt;h2 id=&quot;minification-preprocessing-and-context-specific-optimizations&quot;&gt;Minification: preprocessing &amp;amp; context-specific optimizations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#minification-preprocessing-and-context-specific-optimizations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary-2&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#summary-2&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Content-specific optimizations can significantly reduce the size of delivered resources.&lt;/li&gt;
&lt;li&gt;Content-specific optimizations are best applied as part of your build/release cycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best way to compress redundant or unnecessary data is to eliminate it altogether.
We can’t just delete arbitrary data, but in some contexts where we have content-specific
knowledge of the data format and its properties, it&#39;s often possible to significantly
reduce the size of the payload without affecting its actual meaning.&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;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;span class=&quot;token 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 comment&quot;&gt;/* awesome-container is only used on the landing page */&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token selector&quot;&gt;.awesome-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 120%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token selector&quot;&gt;.awesome-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/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;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;span class=&quot;token comment&quot;&gt;&amp;lt;!-- awesome container content: START --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- awesome container content: END --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;awesomeAnalytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&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;// beacon conversion metrics&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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/optimizing-content-efficiency/minify.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Consider the simple HTML page above and the three different content types that it
contains: HTML markup, CSS styles, and JavaScript. Each of these content types has
different rules for what constitutes valid content, different rules for indicating
comments, and so on. How can we reduce the size of this page?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code comments are a developer’s best friend, but the browser doesn&#39;t need to see them!
Simply stripping the CSS (&lt;code&gt;/* … */&lt;/code&gt;), HTML (&lt;code&gt;&amp;lt;!-- … --&amp;gt;&lt;/code&gt;), and JavaScript (&lt;code&gt;// …&lt;/code&gt;)
comments can significantly reduce the total size of the page.&lt;/li&gt;
&lt;li&gt;A &amp;quot;smart&amp;quot; CSS compressor could notice that we’re using an inefficient way of
defining rules for &amp;quot;.awesome-container&amp;quot; and collapse the two declarations into one
without affecting any other styles, saving more bytes.&lt;/li&gt;
&lt;li&gt;Whitespace (spaces and tabs) is a developer convenience in HTML, CSS, and JavaScript.
An additional compressor could strip out all the tabs and spaces.&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;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;span class=&quot;token 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;.awesome-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 120%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;…&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;awesomeAnalytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/optimizing-content-efficiency/minified.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After applying the above steps, the page goes from 406 to 150 characters,
a 63% compression savings. Granted, it’s not very readable, but it also doesn’t
have to be: you can keep the original page as your &amp;quot;development version&amp;quot; and then
apply the steps above whenever you&#39;re ready to release the page on your website.&lt;/p&gt;
&lt;p&gt;Taking a step back, the above example illustrates an important point: a general-purpose
compressor—say, one designed to compress arbitrary text—could probably
do a pretty good job of compressing the page above, but it would never know to
strip the comments, collapse the CSS rules, or dozens of other content-specific
optimizations. This is why preprocessing/minification/context-aware optimization
can be such a powerful tool.&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; Case in point, the uncompressed development version of the jQuery library is now approaching ~300KB. The same library, but minified (removed comments, etc.) is about 3x smaller: ~100KB. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Similarly, the techniques described above can be extended beyond just text-based assets.
Images, video, and other content types all contain their own forms of metadata
and various payloads. For example, whenever you take a picture with a camera,
the photo also typically embeds a lot of extra information: camera settings,
location, and so on. Depending on your application, this data might be critical
(for example, a photo-sharing site) or completely useless, and you should consider
whether it is worth removing. In practice, this metadata can add up to tens of
kilobytes for every image.&lt;/p&gt;
&lt;p&gt;In short, as a first step in optimizing the efficiency of your assets, build
an inventory of the different content types and consider what kinds of content-specific
optimizations you can apply to reduce their size. Then, after you’ve figured out
what they are, automate these optimizations by adding them to your build and
release processes to ensure that the optimizations are applied.&lt;/p&gt;
&lt;h2 id=&quot;text-compression-with-gzip&quot;&gt;Text compression with GZIP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#text-compression-with-gzip&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary-3&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#summary-3&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;GZIP performs best on text-based assets: CSS, JavaScript, HTML.&lt;/li&gt;
&lt;li&gt;All modern browsers support GZIP compression and will automatically request it.&lt;/li&gt;
&lt;li&gt;Your server must be configured to enable GZIP compression.&lt;/li&gt;
&lt;li&gt;Some CDNs require special care to ensure that GZIP is enabled.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Gzip&quot; rel=&quot;noopener&quot;&gt;GZIP&lt;/a&gt; is a generic compressor that can be applied
to any stream of bytes. Under the hood, it remembers some of the previously seen content
and attempts to find and replace duplicate data fragments in an efficient way.
(If you&#39;re curious, here&#39;s a
&lt;a href=&quot;https://www.youtube.com/watch?v=whGwm0Lky2s&amp;amp;feature=youtu.be&amp;amp;t=14m11s&quot; rel=&quot;noopener&quot;&gt;great low-level explanation of GZIP&lt;/a&gt;.)
However, in practice, GZIP performs best on text-based content, often achieving
compression rates of as high as 70-90% for larger files, whereas running GZIP
on assets that are already compressed via alternative algorithms (for example,
most image formats) yields little to no improvement.&lt;/p&gt;
&lt;p&gt;All modern browsers support and automatically negotiate GZIP compression for all
HTTP requests. You must ensure that the server is properly configured to serve the
compressed resource when the client requests it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Library&lt;/th&gt;
    &lt;th&gt;Size&lt;/th&gt;
    &lt;th&gt;Compressed size&lt;/th&gt;
    &lt;th&gt;Compression ratio&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;jquery-1.11.0.js&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;276 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;82 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;jquery-1.11.0.min.js&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;94 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;33 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;65%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;angular-1.2.15.js&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;729 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;182 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;75%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;angular-1.2.15.min.js&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;101 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;37 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;63%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;bootstrap-3.1.1.css&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;118 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;18 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;bootstrap-3.1.1.min.css&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;98 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;17 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;83%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;foundation-5.css&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;186 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;22 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;88%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;library&quot;&gt;foundation-5.min.css&lt;/td&gt;
  &lt;td data-th=&quot;size&quot;&gt;146 KB&lt;/td&gt;
  &lt;td data-th=&quot;compressed&quot;&gt;18 KB&lt;/td&gt;
  &lt;td data-th=&quot;savings&quot;&gt;88%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The above table shows the savings that GZIP compression produces for a few of the
most popular JavaScript libraries and CSS frameworks. The savings range from 60 to 88%,
and the combination of minified files (identified by “.min” in their filenames),
plus GZIP, offers even more savings.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Apply content-specific optimizations first: CSS, JS, and HTML minifiers.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apply GZIP to compress the minified output.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enabling GZIP is one of the simplest and highest-payoff optimizations to implement,
and yet, many people don&#39;t implement it. Most web servers compress content on your behalf,
and you just need to verify that the server is correctly configured to compress
all the content types that benefit from GZIP compression.&lt;/p&gt;
&lt;p&gt;The HTML5 Boilerplate project contains
&lt;a href=&quot;https://github.com/h5bp/server-configs&quot; rel=&quot;noopener&quot;&gt;sample configuration files&lt;/a&gt;
for all the most popular servers with detailed comments for each configuration flag
and setting. To determine the best configuration for your server, do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find your favorite server in the list.&lt;/li&gt;
&lt;li&gt;Look for the GZIP section.&lt;/li&gt;
&lt;li&gt;Confirm that your server is configured with the recommended settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/images/transfer-vs-actual-size.png&quot; alt=&quot;DevTools demo of actual vs transfer size&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A quick and simple way to see GZIP in action is to open Chrome DevTools and
inspect the “Size / Content” column in the Network panel: “Size” indicates the
transfer size of the asset, and “Content” the uncompressed size of the asset.
For the HTML asset in the preceding example, GZIP saved 98.8 KB during the transfer.&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; Sometimes, GZIP increases the size of the asset. Typically, this happens when the asset is very small and the overhead of the GZIP dictionary is higher than the compression savings, or when the resource is already well compressed. To avoid this problem, some servers allow you to specify a minimum filesize threshold. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Finally, while most servers automatically compress the assets for you when serving them
to the user, some CDNs require extra care and manual effort to ensure that the
GZIP asset is served. Audit your site and ensure that your assets are, in fact,
&lt;a href=&quot;http://www.whatsmyip.org/http-compression-test/&quot; rel=&quot;noopener&quot;&gt;being compressed&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimizing Content Efficiency</title>
    <link href="https://web.dev/performance-optimizing-content-efficiency/"/>
    <updated>2014-03-31T00:00:00Z</updated>
    <id>https://web.dev/performance-optimizing-content-efficiency/</id>
    <content type="html" mode="escaped">&lt;p&gt;Our web applications continue to grow in their scope, ambition, and functionality -- that&#39;s a good thing. However, the relentless march toward a richer web is driving another trend: the amount of data downloaded by each application continues to increase at a steady pace. To deliver great performance we need to optimize delivery of each and every byte!&lt;/p&gt;
&lt;p&gt;What does a modern web application look like? &lt;a href=&quot;http://httparchive.org/&quot; rel=&quot;noopener&quot;&gt;HTTP Archive&lt;/a&gt; can help us answer this question. The project tracks how the web is built by periodically crawling the most popular sites (300,000+ from the Alexa Top 1M list) and recording and aggregating analytics on the number of resources, content types, and other metadata for each individual destination.&lt;/p&gt;
&lt;img alt=&quot;HTTP Archive trends&quot; decoding=&quot;async&quot; height=&quot;217&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 597px) 597px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/JqsYuCtNUMTMm3KsDp5u.png?auto=format&amp;w=1194 1194w&quot; width=&quot;597&quot; /&gt;
&lt;div class=&quot;table-wrapper scrollbar&quot;&gt;
&lt;table class=&quot;&quot;&gt;
&lt;colgroup&gt;&lt;col span=&quot;1&quot; /&gt;&lt;col span=&quot;1&quot; /&gt;&lt;col span=&quot;1&quot; /&gt;&lt;col span=&quot;1&quot; /&gt;&lt;/colgroup&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;&lt;/th&gt;
    &lt;th&gt;50th percentile&lt;/th&gt;
    &lt;th&gt;75th percentile&lt;/th&gt;
    &lt;th&gt;90th percentile&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;HTML&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;13 KB&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;26 KB&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;54 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;Images&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;528 KB&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;1213 KB&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;2384 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;JavaScript&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;207 KB&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;385 KB&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;587 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;CSS&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;24 KB&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;53 KB&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;108 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;Other&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;282 KB&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;308 KB&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;353 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td data-th=&quot;type&quot;&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
  &lt;td data-th=&quot;50%&quot;&gt;&lt;strong&gt;1054 KB&lt;/strong&gt;&lt;/td&gt;
  &lt;td data-th=&quot;75%&quot;&gt;&lt;strong&gt;1985 KB&lt;/strong&gt;&lt;/td&gt;
  &lt;td data-th=&quot;90%&quot;&gt;&lt;strong&gt;3486 KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The above data captures the trend in growth of number of downloaded bytes for popular destinations on the web between January 2013 and January 2014. Of course, not every site grows at the same rate or requires the same amount of data, hence the reason why we are highlighting the different quantiles within the distribution: 50th (median), 75th, and 90th.&lt;/p&gt;
&lt;p&gt;A median site at the beginning of 2014 is composed of 75 requests that add up to 1054 KB of total transferred bytes, and the total number of bytes (and requests) has grown at a steady pace throughout the previous year. This by itself should not be all that surprising, but it does carry important performance implications: yes, internet speeds are getting faster, but they are getting faster at different rates in different countries, and many users are still subject to data caps and expensive metered plans - especially on mobile.&lt;/p&gt;
&lt;p&gt;Unlike their desktop counterparts, web applications do not require a separate installation process: enter the URL and we are up and running -- that’s a key feature of the web. However, to make this happen &lt;strong&gt;we often have to fetch dozens, and sometime hundreds, of various resources, all of which can add up to megabytes of data and must come together in hundreds of milliseconds to facilitate the instant web experience we are aiming for.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Achieving an instant web experience in light of these requirements is no small feat, which is why optimizing content efficiency is critical: eliminating unnecessary downloads, optimizing transfer encoding of each resource through various compression techniques, and leveraging caching whenever possible to eliminate redundant downloads.&lt;/p&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
  
  <entry>
    <title>Adding Interactivity with JavaScript</title>
    <link href="https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/"/>
    <updated>2013-12-31T00:00:00Z</updated>
    <id>https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/</id>
    <content type="html" mode="escaped">&lt;p&gt;JavaScript allows us to modify just about every aspect of the page: content,
styling, and its response to user interaction. However, JavaScript can also
block DOM construction and delay when the page is rendered. To deliver optimal
performance, make your JavaScript async and eliminate any unnecessary JavaScript
from the critical rendering path.&lt;/p&gt;
&lt;h3 class=&quot;hide-from-toc&quot; id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript can query and modify the DOM and the CSSOM.&lt;/li&gt;
&lt;li&gt;JavaScript execution blocks on the CSSOM.&lt;/li&gt;
&lt;li&gt;JavaScript blocks DOM construction unless explicitly declared as async.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScript is a dynamic language that runs in a browser and allows us to alter just about every aspect of how the page behaves: we can modify content by adding and removing elements from the DOM tree; we can modify the CSSOM properties of each element; we can handle user input; and much more. To illustrate this, let&#39;s augment our previous &amp;quot;Hello World&amp;quot; example with a simple inline script:&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;Critical Path: Script&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;var&lt;/span&gt; span &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;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span&#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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;interactive&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change DOM text content&lt;/span&gt;&lt;br /&gt;      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;display &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;inline&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change CSSOM property&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// create a new element, style it, and append it to the DOM&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; loadTime &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;div&#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;      loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;You loaded this page on: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue&#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;loadTime&lt;span class=&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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/script.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;JavaScript allows us to reach into the DOM and pull out the reference to the hidden span node; the node may not be visible in the render tree, but it&#39;s still there in the DOM. Then, when we have the reference, we can change its text (via .textContent), and even override its calculated display style property from &amp;quot;none&amp;quot; to &amp;quot;inline.&amp;quot; Now our page displays &amp;quot;&lt;strong&gt;Hello interactive students!&lt;/strong&gt;&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JavaScript also allows us to create, style, append, and remove new elements in the DOM. Technically, our entire page could be just one big JavaScript file that creates and styles the elements one by one. Although that would work, in practice using HTML and CSS is much easier. In the second part of our JavaScript function we create a new div element, set its text content, style it, and append it to the body.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;page preview&quot; decoding=&quot;async&quot; height=&quot;370&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 717px) 717px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AjyzdxcNFYaEYYgNBBWh.png?auto=format&amp;w=1434 1434w&quot; width=&quot;717&quot; /&gt;
&lt;p&gt;With that, we&#39;ve modified the content and the CSS style of an existing DOM node, and added an entirely new node to the document. Our page won&#39;t win any design awards, but it illustrates the power and flexibility that JavaScript affords us.&lt;/p&gt;
&lt;p&gt;However, while JavaScript affords us lots of power, it creates lots of additional limitations on how and when the page is rendered.&lt;/p&gt;
&lt;p&gt;First, notice that in the above example our inline script is near the bottom of the page. Why? Well, you should try it yourself, but if we move the script above the &lt;em&gt;span&lt;/em&gt; element, you&#39;ll notice that the script fails and complains that it cannot find a reference to any &lt;em&gt;span&lt;/em&gt; elements in the document; that is, &lt;em&gt;getElementsByTagName(‘span&#39;)&lt;/em&gt; returns &lt;em&gt;null&lt;/em&gt;. This demonstrates an important property: our script is executed at the exact point where it is inserted in the document. When the HTML parser encounters a script tag, it pauses its process of constructing the DOM and yields control to the JavaScript engine; after the JavaScript engine finishes running, the browser then picks up where it left off and resumes DOM construction.&lt;/p&gt;
&lt;p&gt;In other words, our script block can&#39;t find any elements later in the page because they haven&#39;t been processed yet! Or, put slightly differently: &lt;strong&gt;executing our inline script blocks DOM construction, which also delays the initial render.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another subtle property of introducing scripts into our page is that they can read and modify not just the DOM, but also the CSSOM properties. In fact, that&#39;s exactly what we&#39;re doing in our example when we change the display property of the span element from none to inline. The end result? We now have a race condition.&lt;/p&gt;
&lt;p&gt;What if the browser hasn&#39;t finished downloading and building the CSSOM when we want to run our script? The answer is simple and not very good for performance: &lt;strong&gt;the browser delays script execution and DOM construction until it has finished downloading and constructing the CSSOM.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In short, JavaScript introduces a lot of new dependencies between the DOM, the CSSOM, and JavaScript execution. This can cause the browser significant delays in processing and rendering the page on the screen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The location of the script in the document is significant.&lt;/li&gt;
&lt;li&gt;When the browser encounters a script tag, DOM construction pauses until the script finishes executing.&lt;/li&gt;
&lt;li&gt;JavaScript can query and modify the DOM and the CSSOM.&lt;/li&gt;
&lt;li&gt;JavaScript execution pauses until the CSSOM is ready.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To a large degree, &amp;quot;optimizing the critical rendering path&amp;quot; refers to understanding and optimizing the dependency graph between HTML, CSS, and JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;parser-blocking-versus-asynchronous-javascript&quot;&gt;Parser blocking versus asynchronous JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/#parser-blocking-versus-asynchronous-javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, JavaScript execution is &amp;quot;parser blocking&amp;quot;: when the browser encounters a script in the document it must pause DOM construction, hand over control to the JavaScript runtime, and let the script execute before proceeding with DOM construction. We saw this in action with an inline script in our earlier example. In fact, inline scripts are always parser blocking unless you write additional code to defer their execution.&lt;/p&gt;
&lt;p&gt;What about scripts included via a script tag? Let&#39;s take our previous example and extract the code into a separate file:&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;Critical Path: Script External&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;app.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;strong&gt;app.js&lt;/strong&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;var&lt;/span&gt; span &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;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span&#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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;interactive&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change DOM text content&lt;/span&gt;&lt;br /&gt;span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;display &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;inline&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// change CSSOM property&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// create a new element, style it, and append it to the DOM&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; loadTime &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;div&#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;loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;You loaded this page on: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;loadTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue&#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;loadTime&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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/split_script.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whether we use a &amp;lt;script&amp;gt; tag or an inline JavaScript snippet, you&#39;d
expect both to behave the same way. In both cases, the browser pauses and
executes the script before it can process the remainder of the document.
However, &lt;strong&gt;in the case of an external JavaScript file the browser must pause to
wait for the script to be fetched from disk, cache, or a remote server, which
can add tens to thousands of milliseconds of delay to the critical rendering
path.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By default all JavaScript is parser blocking. Because the browser does not know what the script is planning to do on the page, it assumes the worst case scenario and blocks the parser. A signal to the browser that the script does not need to be executed at the exact point where it&#39;s referenced allows the browser to continue to construct the DOM and let the script execute when it is ready; for example, after the file is fetched from cache or a remote server.&lt;/p&gt;
&lt;p&gt;To achieve this, we mark our script as &lt;em&gt;async&lt;/em&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;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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token 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;Critical Path: Script Async&lt;span class=&quot;token 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;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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;web performance&lt;span class=&quot;token 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; students!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token 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;awesome-photo.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;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;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;app.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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;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;&lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/performance/critical-rendering-path/split_script_async.html&quot; rel=&quot;noopener&quot;&gt;Try it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Adding the async keyword to the script tag tells the browser not to block DOM construction while it waits for the script to become available, which can significantly improve performance.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/#feedback&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
</content>
    <author>
      <name>Ilya Grigorik</name>
    </author>
  </entry>
</feed>
