<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Boris Schapira</title>
    <description>The latest articles on DEV Community by Boris Schapira (@borisschapira).</description>
    <link>https://dev.to/borisschapira</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F33870%2Fc6604f0f-f159-4e6c-bdc3-40c8dec75988.png</url>
      <title>DEV Community: Boris Schapira</title>
      <link>https://dev.to/borisschapira</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/borisschapira"/>
    <language>en</language>
    <item>
      <title>Cumulative Layout Shift, The Layout Instability Metric</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Mon, 21 Sep 2020 15:11:04 +0000</pubDate>
      <link>https://dev.to/borisschapira/cumulative-layout-shift-the-layout-instability-metric-4g52</link>
      <guid>https://dev.to/borisschapira/cumulative-layout-shift-the-layout-instability-metric-4g52</guid>
      <description>&lt;p&gt;&lt;em&gt;Have you ever started reading an exciting news article but then lose your line because all the text shifted downwards? This happens to me a lot, mostly because of ads loading around the content I’m reading.&lt;/em&gt;&lt;br&gt; &lt;em&gt;This kind of user experience can be frustrating, but until now we’ve had trouble measuring it quantitatively. Cumulative Layout Shift addresses this challenge.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;When you see a web page, you automatically break it down into visual elements. You perceive their relationship to each other according to their arrangement on the page. This is how you can identify where the relevant content is located. If this content moves by itself, or if another element is injected into the layout and moves the others, then you may lose sight of what you are focusing on.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/s-QqF7pkMvE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;LeMonde.fr Home page load. Inserted and moving contents are identified by light blue areas. The contents of about 2/3 of the screen moves during the page load.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;And it’s even worse if you thought the layout was stable, and you were about to interact with the page. For example by clicking on a button (image on the left). If other content appears right before the click and pushes the other content downward (image on the right) you might interact with the wrong element of the page.&lt;/p&gt;  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_320%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2Fweb%2F2020-09-15%2F1.png" alt="Two images of a user holding a phone in their hand. In the second image, a tap is implied." width="320" height="240"&gt;&lt;p&gt;Within a product listing, the user is about to click on an image of a chair, when suddenly a text insert appears, shifting all the content downwards. The user unintentionally clicks on an image of a backpack.&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;In this article, we will discuss the Layout Instability API and its use to compute the Cumulative Layout Shift (CLS). We’ll see how to visualize CLS in Chrome and how to optimize for it. Finally, we will address some of its unusual characteristics and conclude.&lt;/p&gt;  &lt;h2&gt;&lt;span id="layout-instability-api"&gt;A Dedicated In-Browser API…&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Viewing the elements that are shifted when loading and while using a page has been a long-standing need. A decade ago, you would need a custom-configured rendering engine (in the following example, Gecko, the Firefox rendering engine) to show every paint reflow.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This video contains lots of repaint. Don’t play if you are photosensitive or have vestibular disorders.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dndeRnzkJDU"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;In Chrome today, you can use the &lt;a href="https://wicg.github.io/layout-instability/" rel="noopener noreferrer"&gt;Layout Instability API&lt;/a&gt;. Its original intent was to find &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=581518" rel="noopener noreferrer"&gt;more relevant signals than the &lt;code&gt;onload&lt;/code&gt; event&lt;/a&gt; to determine when a page is loaded. Layout stability, or “lack of shift” was one of them. As stated in the API abstract, it “provides web page authors with insights into the stability of their pages based on movements of the elements on the page”. To do that, the API monitors the position of the visual representation of every node that is visible in the viewport. If a node’s visual representation shifts from the previous frame by 3 or more pixel units in either the horizontal or vertical direction, the API notifies a layout shift and &lt;strong&gt;scores it&lt;/strong&gt;.&lt;/p&gt; &lt;h2&gt;&lt;span id="cls-compute"&gt;… Used To Penalize Jank&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Let’s go back to our example:&lt;/p&gt;  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_320%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2Fweb%2F2020-09-15%2F1.png" alt="Two images of a user holding a phone in their hand. In the second image, a tap is implied." width="320" height="240"&gt;&lt;p&gt;Within a product listing, the user is about to click on an image of a chair, when suddenly a text insert appears, shifting all the content downwards. The user unintentionally clicks on an image of a backpack.&lt;/p&gt;    &lt;p&gt;How does the Layout Instability API score this? To compute the layout shift score, the algorithm first evaluates the area affected by the shift and multiplies it by the length of the shift.&lt;/p&gt; 

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/SgMZkHRHOB0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The area affected by the shift, or &lt;strong&gt;impact fraction&lt;/strong&gt;, is the total area of the moved node, from its first position to its final position. Here, 78 % +32 % = 110 %. As you can see, the impact fraction can be greater than100 % (the viewport size).&lt;/p&gt; &lt;p&gt;The length of the shift, or &lt;strong&gt;distance fraction&lt;/strong&gt;, is measured according to the viewport’s largest dimension. So in this example, we’ll consider the height. The existing element moves by a height equivalent to 34 % of the height of the viewport.&lt;/p&gt; &lt;p&gt;In this example, and for this particular layout shift, &lt;strong&gt;the layout shift score&lt;/strong&gt; is:&lt;/p&gt; &lt;p&gt;&lt;em&gt;layout shift score = 110 % (impact fraction) × 34 % (distance fraction) = &lt;strong&gt;0.374&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="https://www.dareboost.com/en/doc/website-speed-test/metrics/cumulative-layout-shift-cls" rel="noopener noreferrer"&gt;The Cumulative Layout Shift (CLS)&lt;/a&gt; metric is the sum of (nearly) all individual layout shift scores.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The 500-millisecond window&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;To prevent websites from being penalized for transitions or animations that are the result of user interaction with the interface, the CLS algorithm does not record the layout shift for 500 ms after each active user interaction with the document (e.g. clicks, type, tap), or any event that directly changes the size of the viewport. We can consider that such shifts, resulting from an action, are expected by the user.&lt;/p&gt;  &lt;p&gt;According to Google, to provide a good experience, sites should strive to have &lt;strong&gt;a CLS of less than 0.1&lt;/strong&gt; for most (75%) users. This is bad news for the developers of the above example!&lt;/p&gt; &lt;p&gt;Keep in mind that the impact fraction and distance fraction are highly dependent on the viewport’s characteristics. A change in your viewport’s dimensions or even orientation can change your layout – adapting responsively to the available space. Thus your impact fractions,distance fractions and, in the end, your Cumulative Layout Shift will change.&lt;/p&gt; &lt;h2&gt;&lt;span id="cls-in-chrome"&gt;How To View Layout Shifts in Chrome&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Layout shifts can be displayed in Chrome.&lt;/p&gt; &lt;ol&gt; &lt;li&gt;In the DevTools, open the Command Menu with Control + Shift + P or Command + Shift + P (macOS)&lt;/li&gt; &lt;li&gt;Start typing ‘Rendering’&lt;/li&gt; &lt;li&gt;Run the “Show Rendering” command.&lt;/li&gt; &lt;li&gt;Enable the &lt;strong&gt;Layout Shift Regions&lt;/strong&gt; checkbox. As you interact with a page, layout shifts are highlighted blue.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;As stated above, this feature may cause flashing. If you are photosensitive or have vestibular disorders, use it with caution.&lt;/p&gt;  &lt;p&gt;Since Chrome 84, you can also visualize Layout Shifts and get information about their attribution (even down to the shifted nodes) in the Performance tab, on the ‘Experience’ line.&lt;/p&gt;  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_320%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2Fweb%2F2020-09-15%2Fperformance.png" alt="A screenshot of the DevTools Performance tab, when zooming and selecting a layout shift." width="320" height="357"&gt;&lt;p&gt;On a timeline, a succession of screens helps to understand the visual sequence. Below, several lines expose what happened at the same time, including the Experience line, that contains red inserts, one for each Layout Shift. At the very bottom, a description gives more precise information about the selected Layout Shift.&lt;/p&gt;    &lt;h2&gt;&lt;span id="optimize-cls"&gt;How To Optimize Your Cumulative Layout Shift&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;A page accumulates layouts shifts throughout its use. Each time new elements are visually inserted without the necessary space to display them being reserved by the browser. These insertions will often be images, but you also have to be careful with ads, web fonts, embedded content, and contents injected following an interaction that generate waiting times of more than 500 ms.&lt;/p&gt; &lt;h3&gt;Images&lt;/h3&gt; &lt;p&gt;When it receives the HTML code for your page, the browser doesn’t know much about the images used in it. With no more information than the URL of an image, the browser does not know its size, so it cannot allocate the proper space for the image to display. This has become even more complex since the advent of Responsive Web Design. The display size of an image often depends on the context.&lt;/p&gt; &lt;p&gt;To give as much information as possible to the browser so that it can do its job to the best of its ability, &lt;strong&gt;always set a width and a height attribute on your &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags (in pixels)&lt;/strong&gt;. Even if these are not the actual display dimensions (which may depend on style rules), the browser will use them to infer the width / height ratio (called aspect-ratio) of the image, and thus calculate the height to be reserved based on the display width defined by the CSS.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Did you know?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Edge, Firefox and Chrome have an internal mapping of aspect-ratio for images that defines both width and height attributes. An experiment is ongoing on Chrome to open the feature to developers.&lt;/p&gt; &lt;pre class="highlight"&gt;&lt;code data-lang="css"&gt;&lt;span class="nc"&gt;.el&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* internal rule for img, using the --webkit prefix (in Chrome)
img[width][height] {
  --webkit-aspect-ratio: attr(width) / attr(height);
}*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;a href="https://css-tricks.com/a-first-look-at-aspect-ratio/" rel="noopener noreferrer"&gt;Learn more about &lt;code&gt;aspect-ratio&lt;/code&gt; with Chris Coyier, on CSS Tricks.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;And of course, remember to &lt;a href="https://blog.dareboost.com/en/2017/10/optimize-images-to-reduce-page-weight-file-formats-tools-and-rwd/#serve-the-right-file-size-regarding-to-the-context" rel="noopener noreferrer"&gt;serve the right file size regarding the context&lt;/a&gt;. Use &lt;code&gt;srcset&lt;/code&gt; to help the browser select the best image in your image set with the same aspect ratio (this depends on the rendering width). Use &lt;code&gt;picture&lt;/code&gt; and &lt;code&gt;source&lt;/code&gt; for different aspect-ratio or different image formats based on the context and browser support.&lt;/p&gt; &lt;h3&gt;Ads, embed, iframes, and on-load dynamically created content&lt;/h3&gt; &lt;p&gt;As with the images, the browser needs to allocate the appropriate space to render the final content. But you can’t give much info to the browser, as you have yourself little information about the future content. In the following I will only talk about ads, because they raise the most challenges. But the mechanics are the same for the other types of injected content.&lt;/p&gt; &lt;p&gt;In the following, we will discuss the impact of content injections on the main page template. It’s worth noting that if an iframe produces CLS within itself, it does not impact the main page.&lt;/p&gt;  &lt;p&gt;More often than not, advertising space is allocated to a bidding service that injects a container into a dedicated node. Then, this space is ‘rented’ to the highest bidder, allocated to a network that then injects an advertisement. The space may be resized several times before the final ad is displayed, and in the case of timed ads, additional injections may occur multiple times during the users session.&lt;/p&gt; &lt;h4&gt;How to prevent layout shifts from happening?&lt;/h4&gt; &lt;p&gt;Explicitly define the space allocated to the ad container. If the ad is smaller than the allocated space, plan a background cover that will skin the available space. If the advertisement is larger than the reserved space, some of it will not be displayed.&lt;/p&gt; &lt;p&gt;Sometimes no advertising fills the area. Plan for visuals of the correct size so that you don’t have to collapse the advertising space and provoke a layout shift. If your network provides you a way (through a JS callback, for example) to inject useful content in the absence of advertising, of course, do not hesitate.&lt;/p&gt; &lt;p&gt;Another way to solve this problem is to position the ads in the negative space left by the content of the site, out of the page flow. If your ad has a fixed position in the page template, and that position does not interfere with the flow of the rest of the content, then inserting the ad does not cause any shift.&lt;/p&gt;  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_320%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2Fweb%2F2020-09-15%2Fnegative_en.png" alt="A capture of a page from LeMonde.fr where a space is reserved for an advertisement in the margin. If the advertisement is larger than expected, it takes up more space in the margin, but does not shift the content." width="320" height="180"&gt;&lt;p&gt;Using negative space to position ads.&lt;/p&gt;    &lt;p&gt;You can also move your advertising slots lower down on your pages. This will prevent the layout shift impact fraction from being too large, but this will likely reduce your revenue.&lt;/p&gt; &lt;h3&gt;Web fonts&lt;/h3&gt; &lt;p&gt;When a browser needs to display text with a web font, it identifies whether the font is needed and available (on the system or in the browser’s cache). If the font is necessary but unavailable, then the browser fetches it. During the fetching phase, the browser follows the &lt;code&gt;font-display&lt;/code&gt; instructions (or lack of) to determine whether it should render the text with a fallback font or allocate the space with invisible text. When the font is available, or if the waiting time is too long, then the browser proceeds with the final rendering.&lt;/p&gt; &lt;p&gt;In other words, whenever the browser has to fetch a font, it allocates the area with text using a fallback font, visible or not. And when the font is finally available, the browser renders the text area again using the web font.&lt;/p&gt; &lt;p&gt;However, the temporary font does not necessarily have the same characteristics as the final one. Baselines, point sizes, kernings can differ and the final text may appear shorter or longer than the temporary text, causing layout shifts.&lt;/p&gt; &lt;p&gt;Every time I need to remember how font display management works, I go back to &lt;a href="https://font-display.glitch.me/" rel="noopener noreferrer"&gt;the font-display playground&lt;/a&gt;, by &lt;a href="https://twitter.com/notwaldorf" rel="noopener noreferrer"&gt;Monica Dinculescu&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;To avoid these layout shifts, you can &lt;a href="https://blog.dareboost.com/en/2020/05/optimize-third-parties-performance/" rel="noopener noreferrer"&gt;speed up font loading&lt;/a&gt;. You can also choose web fonts with characteristics similar to system fonts, or consider the web font as optional the first time the page is loaded. It will then not be used on this page, even if downloaded and cached. Instead, it will be available on the next page. You can read more about this in ‘&lt;a href="https://tech.ebayinc.com/engineering/ebays-font-loading-strategy/" rel="noopener noreferrer"&gt;eBay’s Font Loading Strategy&lt;/a&gt;’ by &lt;a href="https://twitter.com/senthil_hi" rel="noopener noreferrer"&gt;Senthil Padmanabhan&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Content injected more than 500 ms after an interaction&lt;/h3&gt; &lt;p&gt;The CLS algorithm ignores Layout Shifts for 500 ms after each active user interaction with the document or change in viewport size. Thanks to this behavior, most user interactions do not cause layout-shifts that are recorded in the Cumulative Layout Shift.&lt;/p&gt; &lt;p&gt;But you have to make sure your UI will react to the user interaction within the500 ms window. If your UI relies on network requests or heavy javascript processing, shifts might occur after 500 ms and will so be taken into account in the Cumulative Layout Shift value.&lt;/p&gt; &lt;p&gt;To optimize your CLS:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Make sure that your transitions and animations that follow user interaction last less than 500 ms.&lt;/li&gt; &lt;li&gt;Measure and optimize your APIs response time.&lt;/li&gt; &lt;li&gt;Anticipate the result of the network call(s) or long treatment by allocating the result area during the 500 ms, even if it is to be filled later on (you can use &lt;a href="https://uxdesign.cc/the-optimistic-ui-with-react-f1420e317d54" rel="noopener noreferrer"&gt;an optimistic UI pattern&lt;/a&gt;).&lt;/li&gt; &lt;li&gt;Implement a specific UI paradigm for long processing and network call (queuing and completion notification system, modals etc)&lt;/li&gt; &lt;li&gt;Only animate &lt;a href="https://csstriggers.com/" rel="noopener noreferrer"&gt;CSS properties that do not trigger layout changes in Blink&lt;/a&gt;.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Of course, &lt;strong&gt;always test&lt;/strong&gt;. While conducting some experiments to write this article, I discovered that &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1099895" rel="noopener noreferrer"&gt;layout shifts are created when the duration of a &lt;code&gt;translate&lt;/code&gt; transition is 0&lt;/a&gt; (this is fixed now). Edge cases like this will always exist. &lt;a href="https://bugs.chromium.org/p/chromium/issues/list" rel="noopener noreferrer"&gt;Please report them to the Chromium Team&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Tip: two-step processing&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Take the example of a “Load 20 more articles” button at the end of a page. If the processing (aka network call + rendering) takes less than 500 ms, no problem. But if it takes longer than 500 ms, the rendering may cause the footer to shift and increment your Cumulative Layout Shift.&lt;/p&gt; &lt;p&gt;To avoid this, you can monitor the elapsed time and split the task in two parts if need be. Instead of rendering systematically after the network call, you can change the button label to “Show all 20 retrieved items”. This will force users to interact again with the page and grant you 500 additional milliseconds for rendering the content.&lt;/p&gt; &lt;p&gt;Of course, do not hesitate to ask the users to check if the use of the functionality better meets their needs. Optimizing the CLS should not be at the expense of the UX.&lt;/p&gt;  &lt;h2&gt;&lt;span id="wtf"&gt;Counter-intuitive behaviors&lt;/span&gt;&lt;/h2&gt; &lt;h3&gt;Continuous accumulation in Single-Page Applications (SPAs)&lt;/h3&gt; &lt;p&gt;While most performance indicators are related to the loading of the page, the CLS is focused on the whole experience of loading and interacting with a website.&lt;/p&gt; &lt;p&gt;Many websites are structured on a page to page, URL to URL navigation paradigm. For them, the CLS is reinitialized with each navigation. Some sites, on the other hand, are built around a single page the content of which evolves through interactions, through JavaScript. These are called Single-Page Applications (SPAs).&lt;/p&gt; &lt;p&gt;On SPAs (including applications that use progressive enhancement &lt;a href="https://github.com/turbolinks/turbolinks" rel="noopener noreferrer"&gt;turbolinks&lt;/a&gt;-like libraries), the Cumulative Layout Shift &lt;strong&gt;may never stop increasing&lt;/strong&gt; during a user’s sessionsession, as the navigation between contents is not achieved by navigating between pages. The Cumulative Layout Shift will only be collected when the user leaves the page. If the Cumulative Layout Speed value you see in the Search Console (in the ‘&lt;a href="https://blog.dareboost.com/en/2020/06/core-web-vitals-page-experience/" rel="noopener noreferrer"&gt;Core Web Vitals&lt;/a&gt;’ section) seems high, maybe that’s an explanation.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This specific point about Cumulative Layout Shift is particularly important. As it means that the goal of SPA developers should not be to reduce the number of layout shifts, but to design interfaces that don’t produce any layout shift &lt;strong&gt;at all&lt;/strong&gt;. If they don’t, the more popular their interfaces are, the longer the session durations will be, and therefore the higher their reported CLS will be.&lt;/p&gt;  &lt;h3&gt;Scrollbars appearance penalty&lt;/h3&gt; &lt;p&gt;This may seem counterintuitive to some, but horizontal and vertical scrollbars are part of the viewport. A great example of this is they’re included in the &lt;a href="https://drafts.csswg.org/css-values-3/#viewport-relative-lengths" rel="noopener noreferrer"&gt;viewport-percentage length such as &lt;code&gt;vw&lt;/code&gt; or &lt;code&gt;vh&lt;/code&gt;&lt;/a&gt;. This implies that the appearance or disappearance of scrollbars does not modify the viewport size even though it changes the area available for content, and causes layout shift.&lt;/p&gt; &lt;p&gt;Unfortunately, on some Operating Systems, like Windows, scrollbars are hidden until they’re needed, which can lead to a scrollbar missing from First Paint, then added later during the page load, and that may cause layout shifts.&lt;/p&gt; &lt;p&gt;To avoid this behavior, you can add &lt;code&gt;html { overflow-y: scroll }&lt;/code&gt; to enforce a scrollbar at First Paint, or wait for the implementation of CSS Overflow Module Level 4 and the new &lt;code&gt;scrollbar-gutter&lt;/code&gt; property.&lt;/p&gt;  &lt;h3&gt;Impact of the timing-function&lt;/h3&gt; &lt;p&gt;In the following example, we compare two flex arrangements. In the first one, the central element doubles in size when hovered, using an “ease” timing-function. In the second example, a “linear” timing-function is used.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RN_bTHjllVE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As you can see, the second example generates much less Cumulative Layout Shift. To explain this, we need to go back to the Layout Instability API spec, and more precisely, to what is called “&lt;a href="https://wicg.github.io/layout-instability/#sec-unstable-nodes" rel="noopener noreferrer"&gt;Unstable nodes&lt;/a&gt;”.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;A Node N has shifted in a coordinate space C if the starting point of N in C differs from the previous frame starting point of N in C by 3 or more pixel units in either the horizontal or vertical direction.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;This “three pixels between two frames” rule introduces a speed criterion in the instability measurement. All elements moving below this speed are not considered unstable, and these animations do not produce a layout-shift.&lt;/p&gt; &lt;p&gt;Unfortunately, this means that to reduce CLS, some site owners might be tempted to use linear animations, which have a constant speed, rather than ones more intuitive to humans, such as “ease”, that speeds up at the beginning of the animation and slows down at the end.&lt;/p&gt;  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_320%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2Fweb%2F2020-09-15%2Ftimings.png" alt="The linear and ease functions, represented by bezier curves." width="320" height="201"&gt;&lt;p&gt;The linear function has a constant growth. The ease function accelerates until the middle of the time, then slows down.&lt;/p&gt;    &lt;h3&gt;Other strange behaviors of the metric&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;Animated elements that create layout shifts may continue to do so if they are not visible to the user (for example, even with a color that blends with the background). But if you use &lt;code&gt;visibility: hidden&lt;/code&gt;, they won’t.&lt;/li&gt; &lt;li&gt;
&lt;a href="https://web.dev/cls/" rel="noopener noreferrer"&gt;The web.dev CLS page&lt;/a&gt; recommends using &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;translate&lt;/code&gt; to create animations that do not produce layout-shift. However, &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1099895&amp;amp;q=cls&amp;amp;can=2" rel="noopener noreferrer"&gt;a bug in Chromium&lt;/a&gt; seems to create layout-shifts when the transition time is 0 in Chrome, until version 86.&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;&lt;span id="conclusion"&gt;Conclusion&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Cumulative Layout Shift is a metric that measures the layout instabilities of a web page. To optimize it, and &lt;strong&gt;improve the user experience&lt;/strong&gt;, you should avoid injecting content for which the browser has not allocated the right amount of space. There are several techniques that exist for images, but this will, however, make advertising management much more complex.&lt;/p&gt; &lt;p&gt;The way the CLS is calculated results in some unusual features. The current algorithm of CLS is probably not a good fit for Single Page Applications, as the attribution of results at page-level is not properly handled. Thus, &lt;a href="https://blog.dareboost.com/en/2020/06/core-web-vitals-page-experience/" rel="noopener noreferrer"&gt;Core Web Vitals as a ranking signal&lt;/a&gt; might be particularly challenging in such cases.&lt;/p&gt; &lt;p&gt;Keep in mind that CLS is a new measure. We still lack feedback at scale. When in doubt, always focus on improving the User Experience instead of the metric itself. Some CLS optimizations may work against this goal and should be avoided.&lt;/p&gt;  &lt;h3&gt;Browser Support&lt;/h3&gt; &lt;p&gt;Steve Kobes announced that Blink (the Chrome rendering engine) &lt;a href="https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/jF1-M8KWAMU/ubGV4Fx2BgAJ" rel="noopener noreferrer"&gt;intended to implement&lt;/a&gt; such an API in October 2018. Work on the draft Layout Instability API began in May 2019, and the API released with Chrome 77 in September 2019 and later in Edge (80+). Daniel Holbert created a ticket for Firefox in July 2020. We did not find any mention of the Layout Instability API in Safari’s public ticketing platform.&lt;/p&gt; &lt;h2&gt;Resources&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="https://tests.boris.schapira.dev/cls/" rel="noopener noreferrer"&gt;My own Cumulative Layout Shift experiments&lt;/a&gt;&lt;/li&gt; &lt;li&gt;“&lt;a href="https://wicg.github.io/layout-instability/" rel="noopener noreferrer"&gt;Layout Instability API specification&lt;/a&gt;”, by Steve Kobes, Nicolás Peña Moreno &amp;amp; Emily Hanley&lt;/li&gt; &lt;li&gt;“&lt;a href="https://web.dev/cls/" rel="noopener noreferrer"&gt;Cumulative Layout Shift&lt;/a&gt;”, by &lt;a href="https://twitter.com/philwalton" rel="noopener noreferrer"&gt;Philip Walton&lt;/a&gt; and &lt;a href="https://twitter.com/bibydigital" rel="noopener noreferrer"&gt;Milica Mihajlija&lt;/a&gt;
&lt;/li&gt; &lt;li&gt;“&lt;a href="https://web.dev/optimize-cls/" rel="noopener noreferrer"&gt;Optimize Cumulative Layout Shift&lt;/a&gt;” and “&lt;a href="https://addyosmani.com/blog/infinite-scroll-without-layout-shifts/" rel="noopener noreferrer"&gt;Infinite Scroll without Layout Shifts&lt;/a&gt;”, by &lt;a href="https://twitter.com/addyosmani" rel="noopener noreferrer"&gt;Addy Osmani&lt;/a&gt;
&lt;/li&gt; &lt;li&gt;“&lt;a href="https://tamethebots.com/blog-n-bits/web-perf-iv-a-new-hope" rel="noopener noreferrer"&gt;Web Vitals - A New Hope in Web Performance Measurement&lt;/a&gt;”, by &lt;a href="https://twitter.com/davewsmart" rel="noopener noreferrer"&gt;Dave Smart&lt;/a&gt;
&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://twitter.com/DamienJubeau" rel="noopener noreferrer"&gt;Damien Jubeau&lt;/a&gt; and to &lt;a href="https://twitter.com/TheRealNooshu" rel="noopener noreferrer"&gt;Matt Hobbs&lt;/a&gt; for their contributions and for helping me improve my English!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self Restraint</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Wed, 03 Jun 2020 15:00:24 +0000</pubDate>
      <link>https://dev.to/borisschapira/self-restraint-2i76</link>
      <guid>https://dev.to/borisschapira/self-restraint-2i76</guid>
      <description>&lt;p&gt;Sometimes I write a tweet or a blog post and then I delete it.&lt;br&gt;Because the world doesn’t need it.&lt;br&gt;Because it can hurt some people.&lt;br&gt;Because there are other ways.&lt;br&gt;Because I can live without publishing it&lt;br&gt;and my followers deserve that I don’t.&lt;/p&gt;

&lt;p&gt;Please do the same with your JavaScript.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Optimize Third-Party Services Performance</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Tue, 19 May 2020 13:29:49 +0000</pubDate>
      <link>https://dev.to/borisschapira/how-to-optimize-third-party-services-performance-19ha</link>
      <guid>https://dev.to/borisschapira/how-to-optimize-third-party-services-performance-19ha</guid>
      <description>&lt;p&gt;&lt;em&gt;Embedding an existing library or service as a third party can increase productivity, but often has a cost on perceived performance. Once you embed external code, how can you ensure that this code will not affect the performance and interactivity of your site? Here are some ideas for a more efficient third party code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building a Front-End Web project is about fulfilling a set of business requirements through code. You can produce this code yourself or transfer this responsibility to libraries or services that have already proven themselves on the market. &lt;/p&gt;

&lt;p&gt;When you reference one of these libraries or services from a web page rather than embedding it in your code, neither you nor the browser of the visitor has control over this resource, since it is produced, managed and hosted by a third party vendor. These are called "Third Party" (or "3p") resources. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Using third-party resources, in HTML, is usually done through the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag (which allows you to load and execute a script), &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag (which references resources later needed by the page) and &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; tag (which creates a completely different navigation context within the page). They are very commonly used. &lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://almanac.httparchive.org/en/2019/third-parties" rel="noopener noreferrer"&gt;the Web Almanac 2019&lt;/a&gt;,  93% of desktop pages include at least one third-party resource and nearly 76% of these pages query an analytics domain (such as Google Analytics, for example). &lt;/p&gt;

&lt;p&gt;Third parties can concern a wide variety of areas: advertising, analytics, customer relationship, social network integration, marketing, user management, videos... Very often, references to these resources are gathered in a &lt;a href="https://blog.dareboost.com/en/2018/04/how-tag-managers-impact-web-performance/" rel="noopener noreferrer"&gt;tag manager&lt;/a&gt;, which centralizes their management and provides an entry point for &lt;a href="https://blog.dareboost.com/en/2018/06/tag-manager-web-performance-best-practices/" rel="noopener noreferrer"&gt;discussions about the third parties&lt;/a&gt; used on the page. &lt;/p&gt;

&lt;p&gt;Using third parties increases the productivity of your development teams (who delegate some features to these third parties). On the other hand, this will increase your operational cost, since you may have to pay for a software license, and most certainly monitor the proper functioning of this software component that you no longer have control over. &lt;/p&gt;

&lt;p&gt;Note that you generally cannot request any changes to the way the third-party resources or services you use work: the fact that these resources are used by a very large number of sites means that the publisher is sheltered from individual pressures. &lt;/p&gt;

&lt;h2&gt;
  
  
  What about performance?
&lt;/h2&gt;

&lt;p&gt;While often criticized, third parties have an impact on rendering and usage performance that it is important to balance. If we take, for example, the most common JS libraries, served as third parties by CDNs: they are among the most efficiently delivered resources, with efficient minification and obfuscation, often coupled with low-latency CDNs. Although their use often degrades the Start Render, this is more often because &lt;a href="https://dev.to/2017/12/defer-script-to-speed-up-rendering/"&gt;these scripts are loaded synchronously&lt;/a&gt; rather than to their third-party status. &lt;/p&gt;

&lt;p&gt;The biggest impact on performance comes from ads and social network scripts which cost on the network and performance is rarely outweighed by the features they provide to users, at least during the initial page loading phase. &lt;/p&gt;

&lt;p&gt;One example is Facebook's "Like" button. Its interest from a user experience perspective is debatable, and it is certainly not relevant until the user has seen the content of the page. You should therefore always load it "lazyly" (late, in the process of loading the page). &lt;/p&gt;

&lt;p&gt;Quite often, once you have assessed the relevance of your third parties and their respective loading modalities, you will certainly discover that the way you load your third parties can be optimized. &lt;/p&gt;

&lt;h2&gt;
  
  
  Delaying a resource or service loaded too soon.
&lt;/h2&gt;

&lt;p&gt;When a third-party resource (or several) is loaded before all the critical elements of the page have been displayed and became interactive, you may want to delay them. An example would be the loading of Youtube videos, located below the fold, consuming bandwidth even when they are not visible. &lt;/p&gt;

&lt;p&gt;In this case, it will be necessary to revise the declaration of the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; responsible for the inclusion of the third party resource in the site, so that this inclusion occurs later, deferred: either in reaction to an event raised during the loading of other resources or after an event provoked by the user (an issue of Lazy-Loading already discussed for &lt;a href="https://dev.to/2019/03/lazy-loading-faster-webpages-seo-friendly/"&gt;the loading of images&lt;/a&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritizing a resource or service that is too late in the queue
&lt;/h2&gt;

&lt;p&gt;If you are using third parties to define or improve the design (fonts, JS scripts that define the dimensions of elements in the layout), or even to retrieve part of the content to be displayed, you will want to prioritize their loading and usage. However, very often, the use of these resources is slowed down by: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  the &lt;strong&gt;DNS resolution&lt;/strong&gt; of the origin that hosts them -   the &lt;strong&gt;connection&lt;/strong&gt; to this origin -   the &lt;strong&gt;downloading&lt;/strong&gt; of these resources &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to tell the browser the behavior to adopt to optimize their loading? Have a look at &lt;a href="https://dev.to/2020/05/preload-prefetch-preconnect-resource-hints/"&gt;my previous article on Preload and Resource Hints&lt;/a&gt;! &lt;/p&gt;

&lt;h2&gt;
  
  
  The Googles Fonts case
&lt;/h2&gt;

&lt;p&gt;When it comes to web fonts, Google Fonts are predominant: according to the Web Almanac 2019 (&lt;a href="https://almanac.httparchive.org/en/2019/fonts" rel="noopener noreferrer"&gt;"Fonts" chapter&lt;/a&gt;), at least 74% of web font requests come from Google Fonts, and 29% of pages contain a link to a Google Fonts CSS style sheet. &lt;/p&gt;

&lt;p&gt;This type of request presents a real risk because the loading of a CSS stylesheet is synchronous. The browser interrupts the rendering of the page while it requests, downloads, and analyzes the CSS file. The request represents a Single Point of Failure (SPOF): if there is no response, then the page remains frozen. It is very easy to &lt;a href="https://www.dareboost.com/en/doc/website-speed-test/settings/dns-mapping-blackhole" rel="noopener noreferrer"&gt;simulate such a failure with Dareboost&lt;/a&gt; (targeting fonts.googleapis.com). &lt;/p&gt;

&lt;p&gt;To mitigate this, you can use asynchronous loading techniques based on &lt;a href="https://www.filamentgroup.com/lab/load-css-simpler/" rel="noopener noreferrer"&gt;attribute alterations&lt;/a&gt; or &lt;a href="https://github.com/filamentgroup/loadCSS" rel="noopener noreferrer"&gt;JavaScript libraries&lt;/a&gt; that expose the life cycle of your fonts. &lt;/p&gt;

&lt;p&gt;A simpler optimization is to download Google Fonts. A feature offered natively on the Google Fonts site but also available via &lt;a href="https://google-webfonts-helper.herokuapp.com/fonts" rel="noopener noreferrer"&gt;Mario Ranfti's Google Webfont Helper tool&lt;/a&gt; which will help you generate the CSS file to declare them. &lt;/p&gt;

&lt;p&gt;By doing so, however, you will lose the benefit of Google Fonts content negotiation, &lt;a href="https://www.tunetheweb.com/blog/should-you-self-host-google-fonts/" rel="noopener noreferrer"&gt;detailed in this article&lt;/a&gt; by &lt;a href="https://dev.to/tunetheweb"&gt;Barry Pollard&lt;/a&gt;. In short: Google Fonts optimizes the CSS file it delivers to provide the right font formats and character sets for the requesting browser. &lt;/p&gt;

&lt;p&gt;At the moment, the best solution may be to use a resource proxy. On the surface, these are &lt;strong&gt;your&lt;/strong&gt; sub-domains that serve the third-party resources you need. Under the hood, they are web applications that perform resource fetching and caching on external domains, filtering the information sent to those domains ( forwarding what is relevant for content negotiation but not privacy-related data). With such a tool, you serve fonts from your domain, while benefiting from Google Fonts content negotiation. This technique, also available for JavaScript scripts, is well described in this article from Decitre Tech team: "&lt;a href="https://tech.decitre.fr/posts/optimiser-chargement-js-tiers" rel="noopener noreferrer"&gt;Limiting the damage of third party JS loading [FR]&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;This complex technique is not within everyone's reach. An alternative is to use a mix of preload (for the CSS stylesheet) and preconnect (to the domain serving the fonts) to get the best possible optimization.Harry Roberts discusses this subject in detail in an article published today: "&lt;a href="https://csswizardry.com/2020/05/the-fastest-google-fonts/" rel="noopener noreferrer"&gt;The Fastest Google Fonts&lt;/a&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Third-party resources or services provide features to your site, but the way they are loaded may negatively impact the user experience. To optimize their usage, start by determining the tradeoffs that need to be made to prioritize each item. Once these priorities are determined, then you can delay or prioritize third-party loading to get the most out of it, sometimes by delivering them through your domain (first-party), either directly or through a proxy.&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Preload, Prefetch and Preconnect: Speed Up your Website with Resource Hints</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Fri, 08 May 2020 15:14:05 +0000</pubDate>
      <link>https://dev.to/borisschapira/preload-prefetch-and-preconnect-speed-up-your-website-with-resource-hints-1a91</link>
      <guid>https://dev.to/borisschapira/preload-prefetch-and-preconnect-speed-up-your-website-with-resource-hints-1a91</guid>
      <description>&lt;p&gt;&lt;em&gt;Loading a web page requires fetching a whole set of resources which collectively allow the page to be displayed and interacted with. To increase the user’s perception of speed, you may need to influence the order in which these resources are fetched and executed. And that’s where &lt;code&gt;preload&lt;/code&gt; and Resource Hints come in.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;A web page consists of a main HTML document and optional additional resources designed to format it, add media, or behaviors. According to the Web Almanac  2019 (chapter "&lt;a href="https://almanac.httparchive.org/en/2019/page-weight#page-requests" rel="noopener noreferrer"&gt;Page Weight&lt;/a&gt;"), more than half the pages contain more than 68 resources added to the main document. &lt;/p&gt;

&lt;p&gt;Hence we can assume that under normal circumstances, downloading a resource is a recurring task for the browser. This task can be broken down into several steps, including: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Revolve the DNS&lt;/strong&gt; of the resource’s origin
(if necessary, i.e. if the browser has not already done so); &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Connect&lt;/strong&gt; to the origin server
(if necessary, i.e. if the browser is not already connected); &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Fetch the resource&lt;/strong&gt;
(if necessary, i.e. if the resource is not already in the user agent cache and still valid); &lt;/li&gt;
&lt;li&gt;  And – according to the type of resource and the reason for which it was fetched – its evaluation and use. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the browser to download resources more efficiently, you can indicate how to optimize these different steps. &lt;/p&gt;

&lt;p&gt;You can even tell (ask?) the browser to download some resources in advance, to &lt;a href="https://blog.dareboost.com/en/2019/01/synthetic-monitoring-user-journey-scenario/" rel="noopener noreferrer"&gt;improve future browsing experience on your site&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  The directives and how to use them
&lt;/h2&gt;

&lt;p&gt;To leverage resource loading, you can use &lt;code&gt;preload&lt;/code&gt;, &lt;code&gt;dns-prefetch&lt;/code&gt;, &lt;code&gt;preconnect&lt;/code&gt;, and &lt;code&gt;prefetch&lt;/code&gt;. We'll call all of these directives "Resource Hints" in the following, but be aware that &lt;code&gt;preload&lt;/code&gt; has &lt;a href="https://www.w3.org/TR/preload/" rel="noopener noreferrer"&gt;its own specification&lt;/a&gt;, while the other Resource Hints are defined in &lt;a href="https://www.w3.org/TR/resource-hints/" rel="noopener noreferrer"&gt;a separate specification&lt;/a&gt;, mostly because `preload' is not just a hint to the browser, but rather a command. &lt;/p&gt;

&lt;p&gt;To write these directives, you can use either the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; HTML tag or the &lt;code&gt;Link&lt;/code&gt; HTTP response header. As for &lt;a href="https://dev.to/borisschapira/content-encoding-why-and-how-to-use-the-meta-charset-tag-and-the-content-type-header-14pj"&gt;specifying the character set&lt;/a&gt;, we recommend you to use the HTTP header, since it will be taken into account by the browser before it starts interpreting the HTML code for the page. &lt;/p&gt;

&lt;p&gt;In the HTML page body: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
&amp;lt;link href="resource-url" rel="directive" as="ressource-type" crossorigin="value" /&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Through an HTTP header:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
Link: &amp;lt;ressource-url&amp;gt;; rel="prefetch"; as="ressource-type"; crossorigin="value"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Whichever syntax you choose, the parameters are always the same: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The URL&lt;/strong&gt; of the resource, of course&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The directive&lt;/strong&gt; to use&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The type&lt;/strong&gt; to consider for the resource, which allows you to adapt the Content-Security-Policy to the nature of the resource (&lt;a href="https://blog.dareboost.com/en/2016/08/how-to-implement-content-security-policy/" rel="noopener noreferrer"&gt;learn more&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;crossorigin&lt;/code&gt; attribute, which we'll discuss later &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These settings can be used to define 4 directives supported by most modern browsers: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;dns-prefetch&lt;/code&gt;: indicates to the browser that it should perform the resolution of a given domain name (determining the IP to contact) before that domain is used to download resources &lt;/li&gt;
&lt;li&gt;  &lt;code&gt;preconnect&lt;/code&gt;: indicates to the browser that it should connect a given origin, before that domain is used to download resources. Preconnecting involves, like - &lt;code&gt;dns-prefetch&lt;/code&gt;, the DNS resolution, but also the TCP handshake and TLS negotiation (if the page is secure) &lt;/li&gt;
&lt;li&gt;  &lt;code&gt;prefetch&lt;/code&gt;: indicates to the browser that it can download a given resource, even if it is not detected in the page. The resource is downloaded with a low priority &lt;/li&gt;
&lt;li&gt;  &lt;code&gt;preload&lt;/code&gt;: tells the browser that it &lt;strong&gt;must&lt;/strong&gt; download a given resource as soon as possible, with high priority. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;code&gt;dns-prefetch&lt;/code&gt; can be interesting in the context of critical third parties: by resolving the domain upstream, a few milliseconds can be saved cost-effectively.   However, in most cases, you may want to use &lt;code&gt;preconnect' instead of&lt;/code&gt;dns-prefetch', so as to anticipate the whole connection. &lt;/p&gt;

&lt;p&gt;If your site must be compatible with Internet Explorer, which does not support &lt;code&gt;preconnect&lt;/code&gt;, you can use the &lt;code&gt;rel="preconnect dns-prefetch"&lt;/code&gt; syntax . &lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;preload&lt;/code&gt; for resources that you know will be useful very early in the page load but that would not naturally be prioritized by the browser. This makes &lt;code&gt;preload&lt;/code&gt; useless for synchronous scripts present in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, which are already considered by the analyzer to have a high priority. You can use it to increase the priority of execution of an asynchronous script declared in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. &lt;code&gt;preload&lt;/code&gt; is also used to load resources referenced by other resources (such as web fonts, images, or other stylesheets referenced using &lt;code&gt;@import&lt;/code&gt;) to retrieve them while the parent resource is fetched and parsed. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;prefetch&lt;/code&gt; is a directive that sets a very low priority, don’t use it for essential resources. Actually, it can be very relevant for improving navigation on subsequent pages. One of the great use case is to include some &lt;code&gt;prefetch&lt;/code&gt; directives during the authentication of a user, to take advantage of the time it takes them to input their login and password to preload the static resources needed to render the page they will see once authenticated. &lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;crossorigin&lt;/code&gt; attribute
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;crossorigin&lt;/code&gt; attribute – which is optional – is used when fetching resources from origins that are different from the main origin (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin" rel="noopener noreferrer"&gt;CORS&lt;/a&gt;).   For many resources (such as CSS, or images), you don't need to specify it, unless you want to request these resources by passing authentication headers, cookies, etc. (with the &lt;code&gt;use-credentials&lt;/code&gt; value). &lt;/p&gt;

&lt;p&gt;For other types of resources, defined in more recent specifications, &lt;code&gt;crossorigin&lt;/code&gt; must be explicitly stated. This is the case, for example, for fonts (&lt;a href="https://drafts.csswg.org/css-fonts/#font-fetching-requirements" rel="noopener noreferrer"&gt;see the specification&lt;/a&gt;), &lt;strong&gt;even when they come from the main origin&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;But be aware of the implications: for example, if you are using &lt;code&gt;preconnect&lt;/code&gt; on a third party domain from which you are retrieving images &lt;strong&gt;and&lt;/strong&gt; fonts, make two declarations in order to create two connections: one without &lt;code&gt;crossorigin&lt;/code&gt;, for the images, and the other with it, for the fonts. &lt;/p&gt;

&lt;h2&gt;
  
  
  Consume in moderation
&lt;/h2&gt;

&lt;p&gt;Reading this article, you might assume it’s relevant to declare many Resource Hints so that the browser loads the page as quickly as possible to. That is not the case. &lt;/p&gt;

&lt;p&gt;Since it sets a low download priority, you can use &lt;code&gt;prefetch&lt;/code&gt; without any real impact on the current page load. Be careful though: its use will increase data consumption on your site, which can present issues both for you (increased traffic on your server), and your users (unnecessary over-consumption of resources). &lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;preload&lt;/code&gt; sparingly, as it overrides the priorities set by the browser’s analyzer, both in terms of download and execution. For example, imagine that you have an &lt;code&gt;async&lt;/code&gt; script in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Thanks to the &lt;code&gt;async&lt;/code&gt; attribute, its download priority is low. However, once fetched, like any non-deffered script, its parsing and execution interrupt the main thread (you need to use the &lt;code&gt;defer&lt;/code&gt; attribute to change that). If you add a &lt;code&gt;preload&lt;/code&gt; directive matching this resource URL, the browser will fetch it faster, so it will parse it faster, negating the effect of your &lt;code&gt;async&lt;/code&gt; attribute by interuptiing the main thread very early in the page load). &lt;/p&gt;

&lt;p&gt;Though &lt;code&gt;preconnect&lt;/code&gt; cost is low, it is not null. If the open connection is not used quickly, then the &lt;code&gt;preconnect&lt;/code&gt; directives only add extra CPU usage (both client and server) and unnecessary network competition. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[…] use it wisely: each open socket incurs costs both on the client and &amp;gt; server, and you want to avoid opening sockets that might go unused. As always, &amp;gt; apply, measure real-world impact, and iterate to get the best performance &amp;gt; mileage from this feature.&lt;br&gt;&lt;br&gt;
&lt;cite&gt;"&lt;a href="https://www.igvita.com/2015/08/17/eliminating-roundtrips-with-preconnect/" rel="noopener noreferrer"&gt;Eliminating Roundtrips with Preconnect [EN]&lt;/a&gt;", Ilya Grigorik&lt;/cite&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This advice from 2015 is still relevant, particularly for connections to secure origins, for which the validation of certificates adds some CPU and network overhead. &lt;/p&gt;

&lt;p&gt;The same kind of recommendations can be found &lt;a href="https://3perf.com/blog/link-rels/" rel="noopener noreferrer"&gt;in the work of Ivan Akulov&lt;/a&gt;, who even advises to switch to &lt;code&gt;dns-prefetch&lt;/code&gt;, which is cheaper, if more than 4 to 6 domains are concerned. &lt;/p&gt;

&lt;p&gt;As you can see, &lt;em&gt;with great power comes great responsibility&lt;/em&gt;. If you want to get your hands on the priorities generated natively by the browser, then you must proceed in a moderate and responsible way, in order to avoid reproducing network congestion and CPU consumption that would affect your users. This can be very profitable, especially to &lt;a href="https://blog.dareboost.com/en/2020/05/optimize-third-parties-performance/" rel="noopener noreferrer"&gt;optimize third party services (analytics, web fonts, etc.)&lt;/a&gt;. &lt;br&gt;
Like many web performance topics: test, measure and iterate! &lt;/p&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Performance timing: wait for the next frame (when using the User Timing API)</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Thu, 03 Oct 2019 15:10:07 +0000</pubDate>
      <link>https://dev.to/borisschapira/performance-timing-wait-for-the-next-frame-when-using-the-user-timing-api-1i60</link>
      <guid>https://dev.to/borisschapira/performance-timing-wait-for-the-next-frame-when-using-the-user-timing-api-1i60</guid>
      <description>&lt;p&gt;The usual web performance metrics (First Byte, Speed Index…) are very interesting but I often need to add custom temporal markers, based on events that make sense from a business point of view.&lt;/p&gt;

&lt;p&gt;I use the User Timing API (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API" rel="noopener noreferrer"&gt;see on MDN&lt;/a&gt;) to create named timestamps that belong to the browser's performance timeline. As I can retrieve this timeline in Dareboost, I can &lt;a href="https://blog.dareboost.com/en/2018/05/custom-timings-monitoring/" rel="noopener noreferrer"&gt;track their evolution over time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy65890c5h7pxigaidti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy65890c5h7pxigaidti.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;
Some Custom Timings of this site



&lt;p&gt;Using the API in JavaScript is quite simple (and &lt;a href="https://caniuse.com/#feat=user-timing" rel="noopener noreferrer"&gt;broadly supported&lt;/a&gt;), for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// The thing you want to monitor the occurrence of&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// The timestamp&lt;/span&gt;
    &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mark-blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then retrieve the value in your browser developers tools, using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;performance.getEntriesByType('mark');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, I recently&lt;sup id="fnref1"&gt;1&lt;/sup&gt; realized that I often forgot something important: &lt;strong&gt;just because the browser execute some JavaScript code does not mean that the user can see the results of this execution&lt;/strong&gt;. The browser must update the display, and its ability to do so depends on the JavaScript code that follows the piece of code we're interested in.&lt;/p&gt;

&lt;p&gt;In the following example, I inject a 1-second blocking loop after my performance mark, preventing the browser to update of the display.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// The thing you want to monitor the occurrence of&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// The timestamp&lt;/span&gt;
    &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mark-blue-sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// A snippet of code that consumes resources during 1 second&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, in real life, you won't have a simple loop. You will have other tasks that may or may not take a long time. You can't know it and, in fact, you can't even test it, because it all depends on the customer context that you don't control.&lt;/p&gt;

&lt;p&gt;To get around this problem, we can use &lt;code&gt;requestAnimationFrame()&lt;/code&gt; to ask for our mark to be put set before the browser performs the next repaint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// The thing you want to monitor the occurrence of&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mark-blue-sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// The timestamp, before the next repaint&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mark-blue-frame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// A snippet of code that consumes resources during 1 second&lt;/span&gt;
    &lt;span class="c1"&gt;// but we don't care anymore&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see this for yourself, here's &lt;a href="https://tests.boris.schapira.dev/perfmark-animationframe/" rel="noopener noreferrer"&gt;a test page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  IN A NUTSHELL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Call the User Timings API&lt;/strong&gt; to create custom business-related timestamps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encapsulate them&lt;/strong&gt; inside &lt;code&gt;requestAnimationFrame()&lt;/code&gt; callbacks to get to understand how the UI behaves, rather than the code execution.&lt;/p&gt;

&lt;p&gt;If you want to have an idea of the display latency, attach two marks: one after the event to be followed, the other in a &lt;code&gt;requestAnimationFrame()&lt;/code&gt; callback.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Reading "&lt;a href="https://blog.superhuman.com/performance-metrics-for-blazingly-fast-web-apps-ec12efa26bcb" rel="noopener noreferrer"&gt;Performance metrics for blazingly fast web apps&lt;/a&gt;", by Conrad Irwin ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>First Contentful Paint (FCP), Start Render, First Paint. How to properly measure the beginning of page rendering?</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Wed, 18 Sep 2019 13:29:10 +0000</pubDate>
      <link>https://dev.to/borisschapira/first-contentful-paint-fcp-start-render-first-paint-how-to-properly-measure-the-beginning-of-page-rendering-1919</link>
      <guid>https://dev.to/borisschapira/first-contentful-paint-fcp-start-render-first-paint-how-to-properly-measure-the-beginning-of-page-rendering-1919</guid>
      <description>&lt;p&gt;&lt;em&gt;How to properly measure how fast a web page starts to display its content? Several Web performance metrics exist to answer this question, including First Paint, Start Render and one of the newest: First Contentful Paint (FCP). How does FCP stand out, what are its limitations? Let’s dive into the metrics that measure the browser’s early rendering of web pages.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After a click or any other navigation action, a user can only perceive a page is loading if some content has started to be rendered. How do we know the moment this rendering starts? One of the simplest ways of finding when the browser first renders something after navigation is to ask the browser itself. This is called “First Paint”, and one of the earliest web performance metric.&lt;/p&gt;

&lt;p&gt;First Paint, however, can be misleading: the “paint” is from the browser perspective, not the user’s. And a browser can perform a paint that is not visible to a user.  For example, if an element is rendered with the same background as the default background, &lt;strong&gt;First Paint&lt;/strong&gt; is triggered all the same.&lt;br&gt;&lt;br&gt;
Using First Paint to track the performance of your page does not guarantee you’re tracking when something is displayed for your visitors.&lt;/p&gt;

&lt;p&gt;How can we focus on what makes sense to a visitor? That’s the question the &lt;strong&gt;First Contentful Paint&lt;/strong&gt; is trying to answer. According to the &lt;a href="https://w3c.github.io/paint-timing/#first-contentful-paint" rel="noopener noreferrer"&gt;Paint Timing specification&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FCP is the point when the browser renders the first bit of content from the Document Object Model (DOM), which may be text, an image, SVG, or even a canvas element.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Paint Timing 1&lt;br&gt;Editor’s Draft, 13 June 2019&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As for First Paint, the browser returns the information when processing the rendering of web elements, but it additionally checks the element type (text, image, SVG or a canvas).&lt;/p&gt;

&lt;p&gt;First Contentful Paint can be found in Dareboost, WebPageTest or in Google services like &lt;a href="https://blog.dareboost.com/en/2018/06/lighthouse-tool-chrome-devtools/" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt; or Chrome UX Report which data is used in &lt;a href="https://blog.dareboost.com/en/2018/06/google-page-speed-insights-2/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt;. For now, FCP is only available on Chrome and Opera. &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1519410" rel="noopener noreferrer"&gt;Firefox considers to support it&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;Here’s how you can get First Contentful Paint from Chrome DevTools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let fcp = performance.getEntriesByName(``"first-contentful-paint"``)[0].startTime;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, FCP also has a few limitations.&lt;/p&gt;

&lt;p&gt;First, it doesn’t take iframes into account, which can be an issue if your main content is relying on an iframe to be loaded (but that’s definitely an edge case to be avoided).&lt;/p&gt;

&lt;p&gt;Secondly, FCP can be biased by a text node waiting for a pending web font to be rendered. &lt;a href="https://www.dareboost.com/en/report/d_15d6836e290b9986db76db85e?reportIds=d_15d6836e290b9986db76db85e" rel="noopener noreferrer"&gt;In the following example&lt;/a&gt;, we would presume the FCP to be fired around 900 ms, as we don’t see any content before that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FBkAQ3bTLN6eJAi2-wcAytLoeyT_1wZMNCqVeyovF_kqcetg4eg3DgywX73vPUQsnDCoxZ0D2uIhPj5uUZuhW2nOATuYwt222Wf74N9l-foKK2WE9AIYfJF886DpV95vQtJpWe2of" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FBkAQ3bTLN6eJAi2-wcAytLoeyT_1wZMNCqVeyovF_kqcetg4eg3DgywX73vPUQsnDCoxZ0D2uIhPj5uUZuhW2nOATuYwt222Wf74N9l-foKK2WE9AIYfJF886DpV95vQtJpWe2of" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;
The filmstrip of our example



&lt;p&gt;The actual FCP  value is around 600 ms because that’s the time the text node is first rendered by the browser even if the font is not loaded yet, so the text stays “blank” (invisible) for a while. This phenomenon is called Flash Of Invisible Text (FOIT).&lt;/p&gt;

&lt;p&gt;To avoid that behavior on your websites, make sure that you’re using the @font-face CSS directive with a non-default value for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display" rel="noopener noreferrer"&gt;the &lt;code&gt;font-display&lt;/code&gt; descriptor&lt;/a&gt;. If you’re using Google Fonts, please note that the service now encourages its users to use &lt;code&gt;font-display:swap&lt;/code&gt; value. Make sure that your Google Fonts import declaration specifies a value for the “display” parameter in the URL query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="https://fonts.googleapis.com/css?family=Caveat&amp;amp;amp;display=swap" 
 rel="stylesheet"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the main limitations you may be facing with First Contentful Paint is the metric is not bound to the viewport. Wherever is the piece of content displayed, it will trigger FCP, even if the content is not above-the-fold, and thus not visible for a visitor.&lt;/p&gt;

&lt;p&gt;To really track the time at which we’re sure there is something displayed and visible for the user, we have to use another metric: &lt;strong&gt;Start Render&lt;/strong&gt;. The Start Render algorithm is based on video analysis of the page loading, looking for the first altered pixel in the viewport.&lt;/p&gt;

&lt;p&gt;Even if Start Render will trigger regardless of content type (as the First Paint), it’s a great way to track the time when a user can perceive that the page is loading, while avoiding to track browser-related, “technical”, paints.&lt;/p&gt;

&lt;p&gt;Start Render is only available through Synthetic Monitoring tools because a video analysis is required, whereas FCP and First Paint can be directly requested from the browser, making them usable in Real User Monitoring (RUM) as well.&lt;/p&gt;

&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;dl&gt;
    &lt;dt&gt;&lt;strong&gt;First Paint&lt;/strong&gt;&lt;/dt&gt;
    &lt;dd&gt;The first paint action of the browser, from the browser own perspective. Not necessarily visible from a human.&lt;/dd&gt;
    &lt;dt&gt;
&lt;strong&gt;First Contentful Paint&lt;/strong&gt;
&lt;/dt&gt;
    &lt;dd&gt;The first paint action of the browser, from the browser own perspective, concerning a text, an image, an SVG or a Canvas. Iframes are excluded, and text can be painted but still not visible (because of a webfont still being loaded, or outside of the viewport).&lt;/dd&gt;
    &lt;dt&gt;&lt;strong&gt;Start Render&lt;/strong&gt;&lt;/dt&gt;
    &lt;dd&gt;Something is visible by the user in the viewport. Whatever it is, even if it’s only a background.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;With Dareboost, you can measure and monitor these metrics very easily. We’re advising to focus on one of them only, and we would suggest the Start Render as it’s the one with the fewer edge cases.&lt;/p&gt;

&lt;p&gt;If you’re not already one of our amazing customers, do not wait anymore to ask for a trial on our &lt;a href="https://www.dareboost.com/en/tool/website-monitoring" rel="noopener noreferrer"&gt;Synthetic Monitoring Service&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>We Love Speed 2019 on September 20 in Lille, France</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Tue, 30 Jul 2019 13:58:41 +0000</pubDate>
      <link>https://dev.to/borisschapira/we-love-speed-2019-on-september-20-in-lille-france-5c7m</link>
      <guid>https://dev.to/borisschapira/we-love-speed-2019-on-september-20-in-lille-france-5c7m</guid>
      <description>&lt;p&gt;After a most successful &lt;a href="https://blog.dareboost.com/en/2018/08/event-webperf-we-love-speed-2018/" rel="noopener noreferrer"&gt;2018 edition&lt;/a&gt;, Dareboost is proud to keep sponsoring the French Web Performance event: &lt;strong&gt;We Love Speed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Flogo-transparent-bg-1-1024x239.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Flogo-transparent-bg-1-1024x239.png" alt="We Love Speed Logo" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 2019 edition will take place on September 20, in Lille (&lt;a href="https://www.welovespeed.com/en/2019/informations/" rel="noopener noreferrer"&gt;1h hour from Paris by train&lt;/a&gt;), and will be even more interesting than the previous one, including some feedback from Dareboost customers such as &lt;a href="https://www.welovespeed.com/en/2019/line-up/#rex_seloger" rel="noopener noreferrer"&gt;Antonio Gomes Rodrigues (SeLoger.com)&lt;/a&gt; or &lt;a href="https://www.welovespeed.com/en/2019/line-up/#pagesjaunes_top10" rel="noopener noreferrer"&gt;Loïc Troquet (PagesJaunes.fr)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;More than 200 people are expected for this one-day, two-track conference hosting &lt;a href="https://www.welovespeed.com/en/2019/line-up/" rel="noopener noreferrer"&gt;16 talks&lt;/a&gt; (11 in French, 5 in English).&lt;/p&gt;

&lt;p&gt;Given by Web Performance or Web Quality experts who will have – sometimes – crossed the Atlantic (Estelle Weyl, Jérémy Wagner) or the English Channel (Matt Hobbs, Ryan Townsend), when they don’t travel from Sweden (Peter Hedenskog), the talks will address various central web performance topics such as usability, management of optimization projects, JavaScript performance, third-party governance, Progressive Web Apps, image compression, network protocols, CSS and eco-design. &lt;/p&gt;

&lt;p&gt;Their shared experiences, acquired within the IT departments of OUI.sncf, Wikipedia, L’Équipe.fr, Protonmail, Shift Commerce, the United Kingdom government or within the SiteSpeed.io or Fasterize solutions will certainly echo yours, and inspire discussions.&lt;/p&gt;

&lt;p&gt;As in the previous edition, moments of exchange will be arranged so that developers, decision-makers and Web Performance experts can interact in a user-friendly environment, to mutually enrich each other with technical and methodological tips, but also with enlightening anecdotes about their own initiatives.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Fcite-2-1024x576.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Fcite-2-1024x576.png" alt="La CITÉ des échanges" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An independent event in which we believe
&lt;/h2&gt;

&lt;p&gt;Customer Success Manager at Dareboost for almost two years, I have, once again, invested a lot of time and energy into this event, along with a fantastic team of professionals from Fasterize, BrainCracking, Cdiscount and Theodo, all determined to make this event an important moment for the WebPerf in France.&lt;/p&gt;

&lt;p&gt;We have shared our technical and organizational knowledge, but above all we have listened carefully to your expectations to build an enriching, open and grounded conference that will provide you with the opportunity to return to your teams with new perspectives.&lt;/p&gt;

&lt;p&gt;And even if the conf promises to be twice as rich as last year, its price remains the same: 180 € for the entire day. &lt;a href="https://www.welovespeed.com/en/2019/register/" rel="noopener noreferrer"&gt;Get your ticket now&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Dareboost will be on-site with a booth. Feel free to come and talk to us: we are always happy to exchange with our users. Do you want to discover Dareboost before the event? Feel free to &lt;a href="https://www.dareboost.com/en/demo-request?subject=Demande%20d%27essai%20-%20monitoring%20synth%C3%A9tique" rel="noopener noreferrer"&gt;ask us for a free trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other sponsors, without whom the event would not be possible, will also be present. We thank them for their support!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Fsponsors-welovespeed2019-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F07%2Fsponsors-welovespeed2019-1.png" alt="We Love Speed 2019 Sponsors, so far" width="800" height="784"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>conferences</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Measuring Interactivity with TTI: Time To (consistently) Interactive</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Mon, 20 May 2019 10:04:16 +0000</pubDate>
      <link>https://dev.to/borisschapira/measuring-interactivity-with-tti-time-to-consistently-interactive-460l</link>
      <guid>https://dev.to/borisschapira/measuring-interactivity-with-tti-time-to-consistently-interactive-460l</guid>
      <description>&lt;p&gt;&lt;em&gt;When we talk about web performance measurement, what we’re actually trying to determine is the moment when a user can effectively achieve his or her goal. Meaning the users can consult the content they are looking for and/or interact with the page in a satisfactory way. Some metrics endorse rendering actions by the browser, others measure the progress of the display through the recording of a video. However, a great mystery remains: how to properly measure interactivity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For a few years now, Google has been pushing an ambiguous metric: &lt;strong&gt;Time To Interactive&lt;/strong&gt;. What does it mean? Let’s define it and explain how and when to use it (or not).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fcarnival.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fcarnival.jpg" alt="Photo of a carousel in action. The rotational movement creates a fuzzy effect: it is impossible to know with certainty the speed of the merry-go-round." width="760" height="506"&gt;&lt;/a&gt;&lt;/p&gt;
Measuring interactivity is like getting on a moving ride. When can we consider that the carousel is slow enough to consider that we can jump on it? There’s no precise answer.  




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The measurement of interactiveness is a pregnant challenge for Web&lt;br&gt;
Performance experts. Synthetic monitoring solution vendors, especially, find it&lt;br&gt;
difficult to provide a computable metric in the absence of user input.&lt;/p&gt;

&lt;p&gt;Google’s Time To Interactive is a sophisticated measure designed to determine&lt;br&gt;
the ideal conditions for interactivity by monitoring both the JS main thread&lt;br&gt;
activity and the network. It’s quite effective at determining a time when you are sure that an interaction will be seamless.&lt;/p&gt;

&lt;p&gt;However, TTI is also a complex metric to understand and to exploit that does not measure what most people think it measures, which is&lt;br&gt;
the time it takes for a page to become interactive.&lt;/p&gt;

&lt;p&gt;Real User Monitoring (RUM) remains the only way to capture user’s actions and&lt;br&gt;
even there, we still don’t have a single KPI which simply&lt;br&gt;
depicts the relationship between users behavior and the interactivity of the&lt;br&gt;
page over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;span id="why"&gt;The quest for a new metric&lt;/span&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What are we trying to measure?
&lt;/h3&gt;

&lt;p&gt;Accessing a web page is an experience that the web performance world generally describes as 4 moments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The user has confirmation that loading has started.&lt;/li&gt;
&lt;li&gt; The user has enough information in front of them to think that they can
interact with the page.&lt;/li&gt;
&lt;li&gt; The user can interact with the page (this particular moment being dependant
of the type of the interaction).&lt;/li&gt;
&lt;li&gt; The user’s interaction with the page is effortless and intuitive, with no
delays and jank.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Several signals give the user indications that the loading has started: the url and title change, the browser may animate the tab and / or the favicon, the first non-blank pixels appear, then the rest of the page…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.dareboost.com/en/2018/02/speed-index-web-performance/" rel="noopener noreferrer"&gt;Speed Index&lt;/a&gt; and &lt;a href="https://www.w3.org/TR/paint-timing/#first-contentful-paint" rel="noopener noreferrer"&gt;First Contentful Paint&lt;/a&gt; give a good idea of the visual perception of visitors. They help to understand the perceived load of the page. They have limitations that can be identified at a glance by a human being through video or filmstrip because their algorithm is directly related to what is displayed.&lt;/p&gt;

&lt;p&gt;However, when talking about measuring interactivity – points 3 and 4 – things get harder. Truth is, we don’t actually know how to measure it. The only thing we know how to do well is to collect information that allows us to deduce these particular moments.&lt;/p&gt;

&lt;p&gt;For example, Akamai has been looking for new ways to measure user activity for years. They rely on the Boomerang library, created by Philip Tellis. &lt;a href="https://www.welovespeed.com/en/2018/line-up/#ux-and-performance-metrics-that-matters" rel="noopener noreferrer"&gt;Philip came to We Love Speed 2018&lt;/a&gt; to expose the new user experience metrics that the Boomerang team has been collecting to measure page responsiveness: Rage Clicks, Missed Clicks, Dead Clicks, and Cursor Trashing. By analyzing the distribution of this data qualifying user frustration, we can infer approximately when the user expects the page, or a particular component, to be interactive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Frage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Frage.png" alt="Rage Clicks by First Interaction and Visually Ready :&amp;lt;br&amp;gt;
there's a clear linear correlation ; the slope varies between 1.2 and 1.5." width="760" height="427"&gt;&lt;/a&gt;&lt;/p&gt;
There’s a clear linear correlation between rage clicks and 1.2 to 1.5× the time to Visually Ready (when the page would look to the user like they could interact with it –
&lt;a href="https://akamai.github.io/boomerang/BOOMR.plugins.Continuity.html#toc9__anchor" rel="noopener noreferrer"&gt;see the full definition on Boomerang documentation&lt;/a&gt;). 




&lt;p&gt;This type of correlation requires large amounts of data collected from real users, either through JavaScript libraries like Boomerang, or in-browser RUM like the Chrome UX Report. This data can only be collected on production environments with large amounts of visitors.&lt;/p&gt;

&lt;p&gt;Testing optimizations in this environment is risky. Without prior testing, deploying in production can introduce regressions/slowdowns and hurt your business. Moreover, you’ll have to wait to collect large enough volume of data, and it will be difficult to evaluate, because RUM data is not so easy to analyze.&lt;/p&gt;

&lt;p&gt;Synthetic Monitoring solutions can perform accurate performance measurements on all environments, while controlling test contexts. They would be even more useful if they could provide an interactivity metric.&lt;/p&gt;

&lt;p&gt;But since they do not involve real users, they are forced to engage in shenanigans…&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s introduce… Time To (Consistently) Interactive
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Although there are several definitions, we will focus on the definition put forward by Google through their tools and websites.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Interactivity can be considered in two ways: either as a switch between two states (non-interactive and interactive) or as a continuum. Knowing when a page becomes interactive for the first time is interesting but if the interface does not respond quickly, the UX will be very degraded. By "interactivity", we refer here both to the fact that the page is interactive and to the fact that interactions can take place in a satisfactory way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time To Interactive&lt;/strong&gt;, previously known as "Time To Consistently Interactive", is an experimental synthetic metric that attempts to measure when your web application is both visually rendered and interactive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fdanse.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fdanse.jpg" alt="Superposition of several photos of a dancer in movement. Each movement is captured and yet it is impossible to grasp the continuum on a static image." width="760" height="509"&gt;&lt;/a&gt;&lt;/p&gt;
As moving things are difficult to grasp, we often rely on approximations and models.




&lt;p&gt;TTI is an interactivity metric that does not rely on real users interactions. Instead, the algorithm makes an approximation by considering that a satisfactory interaction can only happen in specific conditions, and focuses on determining the prevalence of these conditions.&lt;/p&gt;

&lt;p&gt;To determine the TTI, the algorithm advances along the timeline, performs checks, and redefines its candidate value for the TTI until it finds a moment where all conditions are met. First, it chooses, as the lower limit, when the user feels that the primary content of the page is visible. Several metrics are available for this: the "&lt;a href="https://github.com/WICG/time-to-interactive#definition" rel="noopener noreferrer"&gt;Time To Interactive Explainer&lt;/a&gt;" uses the First Meaningful Paint, but you can also use the First Contentful Paint, &lt;a href="https://github.com/WPO-Foundation/webpagetest/blob/master/docs/Metrics/TimeToInteractive.md" rel="noopener noreferrer"&gt;as WebPageTest does&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then, the TTI’s algorithm verifies that the browser is able to handle the interaction. As many user inputs are handled by client-side JavaScript, working in a single thread environment, the algorithm must then ensure that no long-lasting JavaScript tasks are currently occupying that thread, preventing JS from handling the user inputs right away. &lt;a href="https://github.com/w3c/longtasks" rel="noopener noreferrer"&gt;For the W3C&lt;/a&gt;, a task is "long" if it lasts longer than 50 ms (&lt;a href="https://github.com/w3c/longtasks" rel="noopener noreferrer"&gt;Long Task&lt;/a&gt;). TTI will observe the JS tasks and wait for a 5-second period of time without Long Tasks.&lt;/p&gt;

&lt;p&gt;However, all this is useless if the JS code necessary to handle the interaction is not yet downloaded. Rather than finely observing each HTTP response to see if JavaScript resources are downloaded, the Time To Interactive algorithm will use a signal: it will wait until it observes a period of at least 5 seconds during which it never sees more than 2 resources (all types combined) being downloaded in parallel.&lt;/p&gt;

&lt;p&gt;If one of the conditions (Long Task and Network) is not met, the algorithm moves its candidate value for the TTI forward and resumes observation to find another Long Task and another 5-second network-quiet window after the last observed Long Task. At that point, the candidate value for the TTI corresponds to the end of the last observed Long Task.&lt;/p&gt;

&lt;p&gt;But we’re not finished! At last, the algorithm does not consider a page to be interactive until the browser has finished parsing the document so if the DOMContentLoadedEnd event occurs after our candidate value for TTI, this moment is chosen as the final value for Time To Interactive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Ftti_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Ftti_w.png" alt="A graph summarizing the above explanations." width="760" height="370"&gt;&lt;/a&gt;&lt;/p&gt;
Schematic diagram of the definition, in the
"&lt;a href="https://github.com/WICG/time-to-interactive#definition" rel="noopener noreferrer"&gt;Time To Interactive Explainer&lt;/a&gt;".




&lt;p&gt;&lt;span id="how-to-use-the-tti"&gt;How to use the TTI?&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When you start to look at the performance in terms of display, you quickly discover the Visually Complete, i.e. the moment when the entire rendering of the visible area of the page is finished.&lt;/p&gt;

&lt;p&gt;Time To Interactive is pretty much like Visually Complete: a time marker for the end of something. The main question is "what?". Tim Dresser found out the most adequate way to define this: TTI is a "no jank past this point" metric and that’s something you would want to monitor and optimize or, at least, not deteriorate without good reasons.&lt;/p&gt;

&lt;p&gt;Indeed, the TTI is computed from the indirect observation of both the CPU –&lt;br&gt;
through the JS Long Tasks – and the network activity. If the TTI increases, it definitely means that a JS Long Task happened later than before, during the page load, and it is important to know why. Has a new Long Task been introduced? Is it a previously known tasks pushed back by a new piece of code? Is this a consequence of some newly-implemented third-party dependency?&lt;/p&gt;

&lt;p&gt;As we’ll demonstrate later in the article, this Long Task is not necessarily harmful to your UX (for example, if you &lt;a href="https://blog.dareboost.com/en/2017/12/defer-scripts-to-speed-up-rendering/" rel="noopener noreferrer"&gt;defer your scripts&lt;/a&gt;, then the Long Tasks they produced will occur later) but you can certainly optimize to make sure they don’t happen (for example, you can delegate complex JavaScript algorithms to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;Web Workers&lt;/a&gt;, making them run in background tasks, therefore not occupying the JavaScript main thread).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;span id="disambiguation"&gt;Common misconception about Time To Interactive&lt;/span&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Time to Interactive is not the time until a page is interactive
&lt;/h3&gt;

&lt;p&gt;"Time To Interactive" is a really ambiguous name.&lt;/p&gt;

&lt;p&gt;Even &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive" rel="noopener noreferrer"&gt;in the Lighthouse documentation&lt;/a&gt;, you can read short misleading definitions like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Time to Interactive (TTI) metric measures how long it takes a page to become interactive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, the sentence is followed by a definition of what "interactive" means here, but for someone who wouldn’t read any further, the damage is done.&lt;/p&gt;

&lt;p&gt;As a matter of fact, the Time To Interactive does not measure how long it takes for a page to become interactive, it measures how long it takes to be sure, regarding the conditions, that a interactivity can happen in a satisfactory way, for at least 5 seconds. That’s why the metric was previously known as Time To &lt;strong&gt;Consistently&lt;/strong&gt; Interactive.&lt;/p&gt;

&lt;p&gt;We can totally have a very fast and usable page that, however, has a massive TTI. To do this, all you need is for the page to perform Long Tasks of the shortest possible duration, at a rate sufficient to interrupt the TTI observation window. &lt;a href="https://tests.boris.schapira.dev/longtask/" rel="noopener noreferrer"&gt;This page&lt;/a&gt;, for example, executes a 51ms task every 2 seconds, during a total of 20 seconds and its TTI is over 19 seconds.&lt;/p&gt;

&lt;p&gt;Still, the page is perfectly interactive way sooner than the TTI suggests.&lt;/p&gt;

&lt;h3&gt;
  
  
  In the TTI algorithm, the "network quiet" subwindow is only a signal
&lt;/h3&gt;

&lt;p&gt;TTI is always linked to the last JS long task. The "quiet network" heuristic is just a signal. I’ve seen people asking if they need to improve their waterfall to artificially create cascades containing less than two simultaneous requests. If none of these requests involve a Long Task, you can relax, your TTI will not suffer.&lt;/p&gt;

&lt;p&gt;However, as this is a signal only, it does not guarantee that the JS code required to handle the interaction is available at all. You can have pretty good Time To Interactive and a page that is not interactive – as expected by user – at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google’s TTI is not everyone’s
&lt;/h3&gt;

&lt;p&gt;Every time Google introduces a new concept, there is a strong market demand. But be careful, Time To Interactive is not a standard!&lt;/p&gt;

&lt;p&gt;Akamai’s Boomerang, one of the most famous Real User Monitoring solution, has &lt;a href="https://developer.akamai.com/tools/boomerang/docs/BOOMR.plugins.Continuity.html#toc10__anchor" rel="noopener noreferrer"&gt;its own definition of Time To Interactive&lt;/a&gt;, that differs a lot from Google’s. They use different signals like Frame Rate, Long Tasks, Page Busyness (via &lt;code&gt;setInterval&lt;/code&gt;) and delayed user interactions. Even if they keep the W3C 50ms Long Tasks definition, their window of quiescence is only 500ms long (instead of 5 seconds), which mitigates TTIs from being extended due to isolated tasks.&lt;/p&gt;

&lt;p&gt;During my research, I’ve also found that some Synthetic Monitoring solutions claim to support the Time To Interactive metric but, as with &lt;a href="https://blog.dareboost.com/en/2017/11/load-time-is-out/" rel="noopener noreferrer"&gt;load time&lt;/a&gt;, you should always verify their definition, because some solutions do not hesitate to brand a "TTI" label on other metrics (such as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming/domInteractive" rel="noopener noreferrer"&gt;the domInteractive event&lt;/a&gt;) that have nothing to do with Google’s TTI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time to Interactive is not easy to stabilize
&lt;/h3&gt;

&lt;p&gt;A metric that is not predictable is difficult to understand. In researching this article, we have gathered this evidence that suggests that the TTI is one of those complex metrics, hard to stabilize.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I tried it out and it was a too unstable metric to measure Wikipedia. Here’s an example: &lt;a href="https://phabricator.wikimedia.org/T176369" rel="noopener noreferrer"&gt;https://phabricator.wikimedia.org/T176369&lt;/a&gt;&lt;br&gt;
&lt;cite&gt;Peter Hedenskog, Software Engineer (Contractor), for the Wikimedia Foundation&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  There are few feedbacks on the TTI
&lt;/h3&gt;

&lt;p&gt;There is little data on the correlation of TTI in the wild and none of them allow us to say that it’s more interesting than the existing metrics.&lt;/p&gt;

&lt;p&gt;Based on a first study by Deepanjan Roy (&lt;a href="https://docs.google.com/spreadsheets/d/14xVEkk0yUV9kCaPERLzUpB057hjdV66KP24AyExayh0/edit#gid=0" rel="noopener noreferrer"&gt;a 28-website scoresheet&lt;/a&gt;), Time To Interactive has later been &lt;a href="https://docs.google.com/document/d/1g0J5JIcICFyXYM6ifBF6vNd_qUPIfpf6YAfFHE1TYRE/edit#heading=h.g1vxo77py7yu" rel="noopener noreferrer"&gt;qualified by Tim Dresser&lt;/a&gt;, without much success. To be honest, these correlations are very difficult to obtain: as we can see from Tim’s analysis, the correlation of more stable metrics like FCP in the wild vs. in the lab is not good either.&lt;/p&gt;

&lt;p&gt;I found &lt;a href="https://www.slideshare.net/nicjansma/reliably-measuring-responsiveness" rel="noopener noreferrer"&gt;one study from 2017, by Nic Jansma&lt;/a&gt;, &lt;a href="https://addyosmani.com/blog/usability/" rel="noopener noreferrer"&gt;quoted by Addy Osmani&lt;/a&gt;, where he explains that improving the TTI has a real impact on conversion rate in a real Use Case but the slides don’t give access to the data nor the experimental conditions.&lt;/p&gt;

&lt;p&gt;Other Use Cases available online often consist in removing all JavaScript from the Landing Pages which is a pretty partial move, where other solutions (like downloading and byte-caching the JS in a Service Worker for future use) could have been chosen. Don’t get me wrong, I’m all for reducing the JavaScript to its smallest share, but never at the expense of the &lt;a href="https://www.dareboost.com/en/tool/user-journey-monitoring" rel="noopener noreferrer"&gt;user journey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Time To Interactive is entering a Web Performance landscape that already offers multiple metrics, some of which are easier to understand and comment. Most of the Use Cases I read about Time To Interactive do not clarify whether the existing metrics were sufficient to qualify the situation. Most site owners only monitor and report on 3 or 4 web performance metrics. Before we ask them to drop one of them for this one, I think it’s important that they can get an extensive idea of their respective relevance.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Long Task "50ms" definition creates a threshold effect
&lt;/h3&gt;

&lt;p&gt;The TTI thresholds have the merit of raising awareness of the importance of performance budgets. TTI is kind of a &lt;a href="https://blog.dareboost.com/en/2015/10/performance-budget/" rel="noopener noreferrer"&gt;performance budget&lt;/a&gt;: "the main thread activity must stay under the 50ms budget".&lt;/p&gt;

&lt;p&gt;However, the definition of any threshold has impact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Ftti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Ftti.png" alt="Capture from WebPageTest. The evaluation of the " width="760" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a really simple blog post page, and test it on Desktop with WebPageTest. The page is visually ready and completely interactive as soon as 1.2s. At that moment and during several seconds, a visitor can read and scroll freely. Around 3.5 seconds, a reCaptcha script execution creates a 150ms Long Task (in red, on the bottom bar) that push the Time To Interactive forward. Will this delay be perceived by the visitor? By the way, how long would a delay take to be felt by a visitor?&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://developers.google.com/web/fundamentals/performance/rail" rel="noopener noreferrer"&gt;the RAIL performance model&lt;/a&gt; (Response, Animation, Idle, Load), the user perception of performance delays depends on the nature of the delay. Interaction delays are perceived after ~100ms. A value consistent with &lt;a href="https://www.nngroup.com/articles/response-times-3-important-limits/" rel="noopener noreferrer"&gt;Nielsen’s 1993 post, based on Miller &amp;amp; Card et al. studies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the perceived delay is 100ms, why consider a JS task as long from 50ms? The explanation lies in the Long Task API specification:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The RAIL performance model suggests that applications should respond in under 100ms to user input (for touch move and scrolling, in under 16ms). Our goal with this API is to surface notifications about tasks that may prevent the application from hitting these targets. We surface tasks that take 50ms or more. A website without these tasks should respond to user input in under 100ms: it will take less than 50ms to finish the task that is being executed when the user input is received and less than 50ms to execute the task to react to such user input.&lt;br&gt;
&lt;cite&gt;&lt;a href="https://w3c.github.io/longtasks/#intro" rel="noopener noreferrer"&gt;Long Task API 1&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words: handling an interaction requires both that the browser is able to handle the user input by not being already busy (interactivity) and that is can handle fast enough the potential JS code execution triggered by the user action (responsiveness). As we don’t know the actual response time of the browser to handle the triggered processing, we consider this time should be less than 50ms. That leaves 50ms for the browser to be free enough to react to the input.&lt;/p&gt;

&lt;p&gt;But in practice, all browsers and browsing contexts are different and there are many factors that can influence the time taken by the browser to process a task.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;span id="alternatives"&gt;Interactivity measurement: is TTI enough?&lt;/span&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TTI as a new reference metric?
&lt;/h3&gt;

&lt;p&gt;Creating and promoting a metric is a performative act especially when the metric is defined as THE reference metric for interactivity: when pushed by Google, the metric not only evaluates the Web, it shapes it. SEO/SEM experts highly value it to their customers, companies use it in rankings. Quickly, everyone considers the metric as a reference, without questioning its rationale.&lt;/p&gt;

&lt;p&gt;However, its many limitations, consistent with its definition based on many approximations, make the TTI a rather binary metric. Either the TTI is very low and you can be happy because you are absolutely certain that the web page offers the best conditions for quality interactions ; or it’s not, and you need to investigate further to know what is happening. Some tasks can be delaying the TTI without bothering end-users but the page may also be unusable. You just don’t have any way to distinguish the two possibilities without further investigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fobserve.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fobserve.jpg" alt="A microscope zooming on a sample." width="760" height="504"&gt;&lt;/a&gt;&lt;/p&gt;
A bad TTI is a sign that not all conditions are perfect for interactivity. This does not mean that interactions will necessarily be degraded. More investigation is always needed. 




&lt;h3&gt;
  
  
  A milestone more than an evaluation of a continuum
&lt;/h3&gt;

&lt;p&gt;Time To Interactive is to interactivity what the Visually Complete is to display: a final milestone. What we’re missing is "a Speed Index of interactions" where each Long Task would be weighted by its duration and the time at which it occurs, in relation to other metrics (e. g. rendering metrics) to infer the user’s frustration.&lt;/p&gt;

&lt;p&gt;In the previously mentioned study, Nic Jansma observed the distribution of Long Task durations and found a correlation with conversion. I hope that we will make progress on this subject in the coming years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fnic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fborisschapira%2Fimage%2Ffetch%2Fc_limit%2Cf_auto%2Cq_auto%2Cw_760%2Fhttps%3A%2F%2Fboris.schapira.dev%2Fassets%2Fimages%2F2019-05-16%2Fnic.png" alt="First Page LongTask Time vs. Conversion Rate (left) ;&amp;lt;br&amp;gt;
First Page LongTask Time vs. Session Length (right)" width="760" height="427"&gt;&lt;/a&gt;&lt;/p&gt;
Nic’s study did not observe a decrease in conversion as long as the First Page Long Tasks were shorter than – not 50ms – but 100ms. Isn’t that interesting?




&lt;p&gt;In the meantime, a lot of other metrics exist regarding interactivity, mainly in RUM, where real user activity can be monitored. For example, I think the distribution of &lt;a href="https://developers.google.com/web/updates/2018/05/first-input-delay" rel="noopener noreferrer"&gt;First Input Delays&lt;/a&gt; is an extremely relevant self-explanatory information but this would be a story for another blog post.&lt;/p&gt;

&lt;p&gt;Remember: if you need to understand what’s happening with your JavaScript code in Synthetic Monitoring, you can still &lt;a href="https://blog.dareboost.com/en/2018/05/dogfooding-dareboost-custom-timings/" rel="noopener noreferrer"&gt;use Custom Timings to deploy a full instrumentation&lt;/a&gt;. It’s the best way to grasp what matters to your business.&lt;/p&gt;




&lt;h2&gt;
  
  
  More about interactivity and the Time To Interactive:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A touch of archaeology
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  [1993]
"&lt;a href="https://www.nngroup.com/articles/response-times-3-important-limits/" rel="noopener noreferrer"&gt;Response Times: The 3 Important Limits&lt;/a&gt;",
Jakob Nielsen&lt;/li&gt;
&lt;li&gt;  [2015]
"&lt;a href="https://developers.google.com/web/fundamentals/performance/rail" rel="noopener noreferrer"&gt;Measure Performance with the RAIL model&lt;/a&gt;",
Meggin Kearney, Addy Osmani, Kayce Basques, Jason Miller&lt;/li&gt;
&lt;li&gt;  [July 2016]
"&lt;a href="https://docs.google.com/document/d/11sWqwdfd3u1TwyZhsc-fB2NcqMZ_59Kz4XKiivp1cIg/edit#heading=h.f294oh9v0jlx" rel="noopener noreferrer"&gt;Time To Interactive&lt;/a&gt;",
Tim Dresser, Paul Irish, Brendan Kenny&lt;/li&gt;
&lt;li&gt;  [December 2016]
"&lt;a href="https://docs.google.com/document/d/1jbvwxj_GJtiTTqFM8dsVzCIy5XeKL5qtIAvuimcXb1o/edit" rel="noopener noreferrer"&gt;Update on defining firstInteractive&lt;/a&gt;",
Deepanjan Roy&lt;/li&gt;
&lt;li&gt;  [January 2017]
"&lt;a href="https://docs.google.com/document/d/1pZsTKqcBUb1pc49J89QbZDisCmHLpMyUqElOwYqTpSI/edit" rel="noopener noreferrer"&gt;Evaluating definitions of firstInteractive&lt;/a&gt;",
Deepanjan Roy&lt;/li&gt;
&lt;li&gt;  [August 2017]
"&lt;a href="https://docs.google.com/document/d/1GGiI9-7KeY3TPqS3YT271upUVimo-XiL5mwWorDUD4c/edit#heading=h.k1h25blerz3i" rel="noopener noreferrer"&gt;First Interactive and Consistently Interactive&lt;/a&gt;",
Deepanjan Roy (anchor to the
&lt;a href="https://docs.google.com/document/d/1GGiI9-7KeY3TPqS3YT271upUVimo-XiL5mwWorDUD4c/edit#bookmark=id.1d8nplewhcab" rel="noopener noreferrer"&gt;definition of the TTI&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  [February 2018]
"&lt;a href="https://github.com/WICG/time-to-interactive#definition" rel="noopener noreferrer"&gt;Time To Interactive Explainer&lt;/a&gt;",
Tim Dresser, Deepanjan Roy&lt;/li&gt;
&lt;li&gt;  [May 2018]
"&lt;a href="https://docs.google.com/document/d/1g0J5JIcICFyXYM6ifBF6vNd_qUPIfpf6YAfFHE1TYRE/edit#heading=h.g1vxo77py7yu" rel="noopener noreferrer"&gt;First Input Delay: Correlation with TTI&lt;/a&gt;",
Tim Dresser&lt;/li&gt;
&lt;li&gt;  [January 2019]
"&lt;a href="https://addyosmani.com/blog/usability/" rel="noopener noreferrer"&gt;Web Page Usability Matters&lt;/a&gt;", Addy
Osmani&lt;/li&gt;
&lt;li&gt;  [February 2019]
"&lt;a href="https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics" rel="noopener noreferrer"&gt;User-centric Performance Metrics&lt;/a&gt;",
Philip Walton&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks to &lt;a href="https://twitter.com/henrihelvetica" rel="noopener noreferrer"&gt;Henri&lt;/a&gt;, &lt;a href="https://twitter.com/bluesmoon" rel="noopener noreferrer"&gt;Phillip&lt;/a&gt;, &lt;a href="https://twitter.com/soulislove" rel="noopener noreferrer"&gt;Peter&lt;/a&gt;, and &lt;a href="https://twitter.com/tkadlec" rel="noopener noreferrer"&gt;Tim&lt;/a&gt; for having helped me to shape my ideas, and &lt;a href="https://twitter.com/DamienJubeau" rel="noopener noreferrer"&gt;Damien&lt;/a&gt; for his multiple proofreading and advice.&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Lazy Loading, faster webpages, SEO friendly</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Wed, 20 Mar 2019 16:20:28 +0000</pubDate>
      <link>https://dev.to/borisschapira/lazy-loading-faster-webpages-seo-friendly-11ge</link>
      <guid>https://dev.to/borisschapira/lazy-loading-faster-webpages-seo-friendly-11ge</guid>
      <description>&lt;p&gt;&lt;em&gt;Images are a key content on your website? If you’re serious about your website performance, you have probably optimized them. But have you considered to lazy load your images? Lazy loading images improves the user experience by saving bandwidth for important content first.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Some reject the technique for SEO considerations. But properly lazy loading your images does not prevent them from being indexed. Let’s find out why you should implement lazy load, and how to make sure you build it in a SEO friendly way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Images are everywhere on the Web. Serving the right image in the right context can be really challenging. &lt;a href="https://blog.dareboost.com/en/2017/10/optimize-images-to-reduce-page-weight-file-formats-tools-and-rwd/" rel="noopener noreferrer"&gt;Images need to be optimized&lt;/a&gt;, adapted to its rendering area, and only loaded if required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Images Lazy Loading&lt;/strong&gt; is a set of techniques designed to answer this last requirement. An image will be loaded only if it is useful for the visitor: the download of an image is triggered when it’s needed: after a specific interaction, as a result of a scroll… or never.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://httparchive.org/reports/state-of-images#offscreenImages" rel="noopener noreferrer"&gt;According to HTTPArchive&lt;/a&gt;, 420 KB (median value) could be saved per page by lazy-loading offscreen and hidden images.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.dareboost.com/wp-content/uploads/2019/03/offscreen-images.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F03%2Foffscreen-images-1024x683.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some use cases
&lt;/h2&gt;

&lt;p&gt;There are many concrete cases where Lazy Loading is involved. Let us take a few minutes to cite a few examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E-Commerce Search Results&lt;/strong&gt;. These pages often contain so many results that a lot of products are outside the viewport. Is it useful to download their images? With Lazy Loading, you can delay their loading until the page is scrolled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Carousels&lt;/strong&gt;. You know about them, right? Why should the user load all of the images whereas it will only showcase the first one during several seconds… Lazy load them! Load the first one, and trigger the download of the next when in the background a couple of seconds before the carousel animation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Menus and tabs.&lt;/strong&gt; Images contained in a menu or a tab are often hidden, only displayed after a click. With Lazy Loading, you can delay the loading of the images until the button displaying the element is hovered or clicked.&lt;/p&gt;

&lt;p&gt;Depending on the nature of your page, other cases are possible. No images should be included on your pages without previously asking yourself the question of delaying their download. Because at the end of the day, there are significant performance gains.  &lt;/p&gt;

&lt;h2&gt;
  
  
  The bare necessities
&lt;/h2&gt;

&lt;p&gt;By postponing the loading of images that are not immediately required – or, in some cases, not loading them at all – the browser saves resources (bandwidth as well as CPU). The page loads faster and the user experience is improved as saved resources can be affected to more critical content. There are also server-side gains. The CPU and bandwidth required to delivered the resources are subjected to less stress, reducing the hosting and/or CDN costs.&lt;/p&gt;

&lt;p&gt;As said in the introduction, Lazy Loading do not prevent your images from being indexed by search engines. But it can be tricky and all the techniques are not equals, as all the best practices are not implemented by the various libraries and plugins available on the market. To preserve your organic SEO, you need to understand how Lazy Loading works, and how to use it safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  LazyLoad with JavaScript
&lt;/h2&gt;

&lt;p&gt;In a perfect world, the browser would automatically lazy load the images. This may be the case in the future, as a &lt;a href="https://github.com/w3c/webappsec-feature-policy/issues/193" rel="noopener noreferrer"&gt;Lazyload Feature Policy&lt;/a&gt; is under study, but we’re not there yet. In the meantime, we have to explore other solutions, every one of them implying a modification of the HTML markup and the addition of a JavaScript (JS) dependency.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;em&gt;You don’t need to – and &lt;strong&gt;shouldn’t&lt;/strong&gt; – lazy load all your images. If you know that some images will be displayed most of the time , let them be loaded and rendered normally. Lazy Loading is only recommended for the other images. Do not add complexity when it’s not required!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The most traditional solution consists of using JS to reassess, at regular intervals and for each image (or each element displaying an image as a background), if it needs to be loaded. High-performance libraries such as &lt;a href="https://github.com/aFarkas/lazysizes" rel="noopener noreferrer"&gt;lazysizes&lt;/a&gt; are built on this paradigm and are compatible with older browsers. lazysizes can even detect if the User-Agent is able to scroll and, if not, load the images right away.&lt;/p&gt;

&lt;p&gt;However, running those tests so regularly has a cost. This cost can be avoided for web browsers supporting the Intersection and Mutation Observer APIs (that provide the ability to react to specific DOM situations rather than having to test continuously). &lt;a href="https://github.com/malchata/yall.js" rel="noopener noreferrer"&gt;yall.js&lt;/a&gt; and &lt;a href="https://apoorv.pro/lozad.js/" rel="noopener noreferrer"&gt;lozad.js&lt;/a&gt; are good examples of this condition-based technique (they are only compatible &lt;a href="https://caniuse.com/#feat=intersectionobserver" rel="noopener noreferrer"&gt;with modern browsers&lt;/a&gt;, but you can use &lt;a href="https://github.com/w3c/IntersectionObserver/tree/master/polyfill" rel="noopener noreferrer"&gt;a polyfill&lt;/a&gt; to emulate the missing feature for older browsers).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;em&gt;As the browser may interpret any omission of &lt;code&gt;src&lt;/code&gt; as an error, I strongly recommend that you still define the &lt;code&gt;src&lt;/code&gt; attribute value, using a really small transparent image placeholder, even inline, like:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whichever JavaScript solution you choose on the client side, you must modify your backend to return the right HTML code. The HTML markup for the lazy-loading of an image is always similar: the final value of the &lt;code&gt;src&lt;/code&gt; attribute is temporarily placed in a &lt;code&gt;data-src&lt;/code&gt; attribute which prevents the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element from loading the final image right away.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Lazy loaded image: before --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;data-src=&lt;/span&gt;&lt;span class="s"&gt;"garden.jpg"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"placeholder.jpg"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"js-lazyload"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dat…"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Lazy loaded background image: before --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-class=&lt;/span&gt;&lt;span class="s"&gt;"bg-image-garden"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container js-lazyload"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The library identifies its target images through an attribute, quite often using a specific class (for example, here, we are using the &lt;code&gt;js-lazyload&lt;/code&gt; class). When the library detects it’s time to load the image, the &lt;code&gt;data-src&lt;/code&gt; attribute is used to populate the &lt;code&gt;src&lt;/code&gt; attribute and the browser starts loading the image. The technique is the same for other media types (video, iframes) or images adapted for responsive web design (for example, the &lt;code&gt;data-srcset&lt;/code&gt; attribute can be used to temporarily retain the final value of the &lt;code&gt;srcset&lt;/code&gt; attribute).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Lazy loaded image: after --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"garden.jpg"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"js-lazyload"&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Lazy loaded background image: after --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container js-lazyload bg-image-garden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No JavaScript? Fallback with style (and &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt;).
&lt;/h2&gt;

&lt;p&gt;Search engine bots, such as Googlebots, are crawlers that browse the web for the purpose of content indexing. No one knows for sure when the Googlebots will execute JavaScript on their pages, and at what capacity. As &lt;a href="https://www.stephanboyer.com/post/122/does-google-execute-javascript" rel="noopener noreferrer"&gt;demonstrated by Stephan Boyer in 2016&lt;/a&gt; and later confirmed by &lt;a href="https://youtu.be/PFwUbgvpdaQ?t=845" rel="noopener noreferrer"&gt;Tom Greenaway at Google IO 2018&lt;/a&gt;, Googlebots do not execute JavaScript during their first visit. The final render can actually arrive several days later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because Googlebots actually runs two waves of indexing across web content, it’s possible some details might be missed.&lt;br&gt;
&lt;cite&gt;Tom Greeaway&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like some images.&lt;/p&gt;

&lt;p&gt;Because if JavaScript properly executed, lazy loaded images will not be handled by it and the &lt;code&gt;src&lt;/code&gt; attribute is never populated, preventing the browser from starting the download and displaying the images.&lt;/p&gt;

&lt;p&gt;How to serve these images despite the absence of JavaScript? There’s a specific HTML element you can use: &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt;. The content of an &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; element is displayed only if scripting features are not supported or are disabled. That’s exactly what we need!&lt;/p&gt;

&lt;p&gt;So if your HTML response contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;data-src=&lt;/span&gt;&lt;span class="s"&gt;"garden.jpg"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dat…"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A spacious garden dominated by a large pine tree."&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lazyload"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"garden.jpg"&lt;/span&gt;  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A spacious garden dominated by a large pine tree."&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  when JavaScript is available, only the first &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element will be displayed;&lt;/li&gt;
&lt;li&gt;  when JavaScript is not available, both &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements are considered during the page display. The second one (in the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; element), is displayed and indexable by search engines. The technique, &lt;a href="https://www.youtube.com/watch?time_continue=4308&amp;amp;v=7m-cd8XXovQ" rel="noopener noreferrer"&gt;confirmed by John Mueller&lt;/a&gt;, Webmaster Trends Analyst at Google, is exactly the same for background images:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-class=&lt;/span&gt;&lt;span class="s"&gt;"bg-image-garden"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container js-lazyload"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container bg-image-garden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        … A spacious garden dominated by a large pine tree. …
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beware: don’t miss adding a specific style that will be applied when JavaScript is not available, hiding the non-lazy-loaded images.&lt;/p&gt;

&lt;p&gt;You may be afraid of the resulting verbose HTML related to code duplication. Don’t worry, your HTML documents have to be compressed with gzip or brotli before being sent on the network, hence a marginal impact in transfer size (if you’re not sure your website is properly using compression, &lt;a href="https://www.dareboost.com/" rel="noopener noreferrer"&gt;audit your pages on Dareboost&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Of course, it remains true that entering all these tags is tedious. When managing responsive images, artistic direction… the markup of images can be very, very complex. So anyway, you should not enter this HTML code manually: dealing automatically with this kind of complexity should be the work of your CMS or a task of your contribution workflow whatever it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.dareboost.com/wp-content/uploads/2019/03/guardians_rwd_image-1.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.dareboost.com%2Fwp-content%2Fuploads%2F2019%2F03%2Fguardians_rwd_image-1.png" width="686" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mark-up an image from The Guardian, even before the implementation of a Lazy Loading&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the implementation
&lt;/h2&gt;

&lt;p&gt;Once you’ve implemented Lazy Loading, you’ll need to test that it works. The simplest solution is, of course to run a &lt;a href="https://www.dareboost.com/en/tool/website-analysis" rel="noopener noreferrer"&gt;full web performance diagnosis&lt;/a&gt; with Dareboost to detect if all the images outside of the viewport are lazyloaded. If it’s not the case, we’ll tell you and give you the URLs of the images for which loading can be postponed.&lt;/p&gt;

&lt;p&gt;If you have conditioned the loading of your images to a browser or a custom event, feel free to use &lt;a href="https://www.dareboost.com/en/doc/analysis-report/timeline-waterfall" rel="noopener noreferrer"&gt;your report’s Waterfall&lt;/a&gt; to check that the loading of images follows the correct sequence. In the case of a custom event, feel free to also use a &lt;a href="https://blog.dareboost.com/en/2018/05/custom-timings-monitoring/" rel="noopener noreferrer"&gt;Custom Timing&lt;/a&gt;: you’ll be able to find the event in the Waterfall.&lt;/p&gt;

&lt;p&gt;It may also need to do manual tests. Open your browser on the concerned webpage, open the Developper Tools and select the Network tab (every modern browser features it). Empty the network stack to better visualize new calls, then provoke the interaction meant to start the lazy loading.  &lt;/p&gt;

&lt;p&gt;Here is an example on Chrome, with the Lazy Loading activated during scrolling:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Z4jRe3KRcf4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You may consider automating these tests by using browser-based tools to perform tests. Puppeteer is one of them and &lt;a href="https://github.com/GoogleChromeLabs/puppeteer-examples/blob/master/lazyimages_without_scroll_events.js" rel="noopener noreferrer"&gt;can be used to test&lt;/a&gt; the behavior of your lazy loading on Chrome or Chromium, to make sure that your real users will see your images.&lt;/p&gt;

&lt;p&gt;To verify that crawler bots will also see your images, you can ask Google itself, using the URL Inspector tool of the &lt;a href="https://search.google.com/search-console" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt;. You will view your page exactly as fetch by Google. Just insert your URL for Googlebot to test your page and screenshot the result to confirm that your &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; fallback is working.&lt;/p&gt;




&lt;p&gt;Here we are, you now know everything there is to know about Images Lazy Load, its SEO impact and the best way to get around it. Let’s trim some pages!&lt;/p&gt;

</description>
      <category>images</category>
      <category>webperf</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Content Encoding: why and how to use the meta charset tag and the Content-Type header</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Mon, 19 Nov 2018 14:44:58 +0000</pubDate>
      <link>https://dev.to/borisschapira/content-encoding-why-and-how-to-use-the-meta-charset-tag-and-the-content-type-header-14pj</link>
      <guid>https://dev.to/borisschapira/content-encoding-why-and-how-to-use-the-meta-charset-tag-and-the-content-type-header-14pj</guid>
      <description>&lt;p&gt;Improving the speed at which a web page is displayed often means making the browser’s life as easy as possible. When the browser receives an HTTP response, it actually receives text encoded in bytes, where each byte or sequence of bytes represents a given character. If the browser does not have a clear information about the used encoding, it will waste time trying to guess and may fail in some cases.&lt;/p&gt;

&lt;p&gt;Although the Web is intended to be universal, the various human groups that use it have their own specificities. One of these specificities is language, especially when written. All textual content is composed of characters from a directory intended for a type of use. Hiraganas, for example, are phonetic system intended for the unambiguous transcription of the Japanese language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F75z7ckyyklwc4618qpl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F75z7ckyyklwc4618qpl4.png" alt="Hiragana" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;
Table showing the writing direction of hiraganas&lt;br&gt;by Karine WIDMER (&lt;a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="noopener noreferrer"&gt;CC-BY-SA-3.0&lt;/a&gt; · &lt;a href="https://commons.wikimedia.org/wiki/File:Table_hiragana.svg" rel="noopener noreferrer"&gt;Source&lt;/a&gt;   




&lt;p&gt;To be able to designate each character unambiguously, we must assign a unique identifier to each of them. The whole set of identifiers will be called a character set. Once this correspondence table has been defined, each character need be converted into a sequence of bytes so that we can store or share them between computers. This is called character encoding.&lt;/p&gt;

&lt;p&gt;Imagine that I use a character set to write text and a corresponding encoding to convert it to bytes, which I later send to you. How would you decode it, and read the content, without knowing which encoding, or set, I used? Eventually, you would have to use some of the most common character set &amp;amp; encodings you know, expecting the result to make sense… What could go wrong?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Replace a semicolon (;) with a greek question mark (;) in your friend’s JavaScript and watch them pull their hair out over the syntax error.&lt;br&gt;&lt;br&gt;
&lt;cite&gt;Ben Johnson (&lt;a class="mentioned-user" href="https://dev.to/benbjohnson"&gt;@benbjohnson&lt;/a&gt;), &lt;a href="https://twitter.com/benbjohnson/status/533848879423578112" rel="noopener noreferrer"&gt;November 16, 2014&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So yeah… not a great idea.&lt;/p&gt;

&lt;p&gt;For example, the bit sequence 1100 0011 1010 1001 represents the character "é" in the UTF-8 encoding. If you decode this sequence assuming you have to use the Latin-1 encoding and not UTF-8, you will read "Ã ©".&lt;br&gt;&lt;br&gt;
In Latin-1, the character "é" is represented by the sequence 1110 1001.&lt;/p&gt;

&lt;p&gt;When the browser receives bytes from your server, it needs to identify the collection of letters and symbols that were used in writing the text that was converted into these bytes, and the encoding used for this conversion, in order to reverse it. If no information of this kind has been transmitted, the browser will try to find recognizable patterns within the bytes to determine the encoding itself, and eventually try some common charsets, which will take time, delaying further processing of the page.&lt;/p&gt;

&lt;p&gt;To speed up the display of your pages, you must specify the content encoding into your HTTP response.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to choose the right character set?
&lt;/h2&gt;

&lt;p&gt;There was a time when hundreds of character encodings coexisted, all limited and not able to contain enough characters to cover all the languages of the world. Sometimes, no encoding was adequate for all letters in a single language.&lt;/p&gt;

&lt;p&gt;Nowadays, Unicode – a universal character set, defining all the characters necessary to write the majority of languages – has become a standard, no matter what platform, device, application or language you’re targeting. UTF-8 is one of the Unicode encodings and the one that should be used for Web content, according to the W3C:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everyone developing content, whether content authors or programmers, should use the UTF-8 character encoding, unless there are very special reasons for using something else. (If you decide to not use UTF-8, you must choose one of the few encodings that are interoperably implemented across all browsers.)&lt;br&gt;&lt;br&gt;
&lt;cite&gt;"&lt;a href="https://www.w3.org/International/getting-started/characters" rel="noopener noreferrer"&gt;Introducing Character Sets and Encodings&lt;/a&gt;", W3C&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Note: if you’re using a database to store your content on the server side, you may be tempted to also use the "utf-8" charset too. Beware: on MySQL and MariaDB, it’s an alias for "utf8mb3", a UTF-8 encoding called "Basic Multilingual Plane" – or BMP – that only stores a maximum of three bytes per code point. Instead, you’d rather use "utf8mb4", an encoding that stores a maximum of four bytes per code point. Otherwise, you won’t be able to use some popular characters, such as 🚀, otherwise known as "U+1F680 ROCKET"!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to advertise your character encoding… and the best way to do it.
&lt;/h2&gt;

&lt;p&gt;Before going any further, let’s take a look at the vocabulary in use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Historically, the terms "character encoding", "character map", "character set" and "code page" were synonymous in computer science[…]. But now the terms have related but distinct meanings,[…] Regardless, the terms are still used interchangeably, with character set being nearly ubiquitous.&lt;br&gt;&lt;br&gt;
&lt;cite&gt;"&lt;a href="https://en.wikipedia.org/wiki/Character_encoding#Character_sets,_character_maps_and_code_pages" rel="noopener noreferrer"&gt;Character encoding&lt;/a&gt;", Wikipedia&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We find this use of "character set" or "charset" to designate, in reality, an encoding, in the HTML specifications. We will do the same in the rest of this article.&lt;/p&gt;

&lt;p&gt;One of the easiest ways to specify a charset in an HTML page is to put in a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag in the element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declaring a character set this way &lt;a href="https://www.w3.org/TR/html5/document-metadata.html#specifying-the-documents-character-encoding" rel="noopener noreferrer"&gt;requires certain constraints to be respected&lt;/a&gt;, one of them being that the element containing the character encoding declaration must be serialized completely within the first 1024 bytes of the document, to ensure that the browser will receive the information with the first IP packets transiting through the network and can use it to decode the rest of the document. As the charset &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag is the only one with this kind of requirement, the most common tip is to place it directly after the element opening tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re afraid to forget this, don’t worry. This is obviously one of the checks that Dareboost will perform for you within our &lt;a href="https://www.dareboost.com/en/tool/website-analysis" rel="noopener noreferrer"&gt;website quality analysis tool&lt;/a&gt;. However, you may find yourself in a situation where this declaration is not sufficient, and the browser does not take it into account. Why? Because the Content-Type metadata of the page may indicate another character set and in the event of a conflict, this information – defined in the page HTTP headers – has priority.&lt;/p&gt;

&lt;p&gt;To make sure of the information transmitted through the page metadata, you can use &lt;a href="https://www.dareboost.com/en/doc/analysis-report/timeline-waterfall" rel="noopener noreferrer"&gt;our Timeline / Waterfall feature&lt;/a&gt;. Unfold the detailed values of your main document to view the response HTTP headers, including the Content-Type header, containing the encoding metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fm347mpxur8ruczgvl395.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fm347mpxur8ruczgvl395.png" alt="Content Type Header in an HTTP response" width="273" height="86"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To change this HTTP header, you may need the help of the person who managed the server, whereas it’s your hosting service provider or a person in charge in your organization, because the configuration of the HTTP headers is very specific to the web server in use, and you’ll need the appropriate administrative rights to be able to modify those server settings.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;Apache 2.2+&lt;/strong&gt;, the configuration of UTF-8 as a default character set for your &lt;code&gt;text/plain&lt;/code&gt; and &lt;code&gt;text/html&lt;/code&gt; files involves &lt;a href="https://httpd.apache.org/docs/2.2/en/mod/core.html#adddefaultcharset" rel="noopener noreferrer"&gt;the &lt;code&gt;AddDefaultCharset&lt;/code&gt; directive&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AddDefaultCharset utf-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other types of files, you'll need &lt;a href="https://httpd.apache.org/docs/current/en/mod/mod_mime.html#addcharset" rel="noopener noreferrer"&gt;the &lt;code&gt;AddCharset&lt;/code&gt; directive&lt;/a&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AddCharset utf-8 .js .css …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On &lt;strong&gt;nginx&lt;/strong&gt;, you’ll need to make sure that &lt;a href="http://nginx.org/en/docs/http/ngx_http_charset_module.html" rel="noopener noreferrer"&gt;the ngx_http_charset_module is loaded&lt;/a&gt;, then use the &lt;code&gt;charset&lt;/code&gt; directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;charset utf-8;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here too, it is possible to refine the scope so that other types of files than &lt;code&gt;text/html&lt;/code&gt; are delivered in utf-8, using the directive &lt;code&gt;charset_types&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;charset_types text/html text/css application/javascript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you can also configure the &lt;code&gt;Content-Type&lt;/code&gt; HTTP header from your server-side scripting code. For example, in &lt;strong&gt;PHP&lt;/strong&gt;, you can use &lt;a href="http://php.net/manual/en/function.header.php" rel="noopener noreferrer"&gt;the header() network function&lt;/a&gt;. Don’t forget to define the Media Type (or MIME type) of the body of the response, in addition to the character set.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type: text/html; charset=utf-8'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Beware: if your pages are delivered by a Content Delivery Network (CDN), you may have to configure the &lt;code&gt;Content-Type&lt;/code&gt; header in the CDN configuration, as most of them don’t pass on the headers they find on your servers.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.iana.org/assignments/media-types/media-types.xhtml" rel="noopener noreferrer"&gt;The IANA Media Types list&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://www.unicode.org/" rel="noopener noreferrer"&gt;The Unicode website&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  "&lt;a href="https://www.w3.org/International/articles/definitions-characters/#httpheader" rel="noopener noreferrer"&gt;Character encodings: Essential concepts&lt;/a&gt;", on the W3C Internationalization website&lt;/li&gt;
&lt;li&gt;  Still thinking that Character Encoding is a trivial issue? Look at "&lt;a href="https://www.youtube.com/watch?v=yQaRUEwEKxE" rel="noopener noreferrer"&gt;Anatomy of a Critical Security Bug&lt;/a&gt;", by Andrew Nacin at Loop Conf 2015.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>headers</category>
      <category>browser</category>
      <category>webdev</category>
    </item>
    <item>
      <title>One hosts file to block them all</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Thu, 13 Sep 2018 14:35:57 +0000</pubDate>
      <link>https://dev.to/borisschapira/one-hosts-file-to-block-them-all-1kf9</link>
      <guid>https://dev.to/borisschapira/one-hosts-file-to-block-them-all-1kf9</guid>
      <description>&lt;p&gt;As a field expert, people often ask me how to improve websites' performance. Sometimes, they also ask me how to improve the Web's performance on their own machine, for their own browsing experience. In that case, my answer is always the same: the lowest hanging fruit is most certainly the &lt;strong&gt;hosts&lt;/strong&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the dirt away
&lt;/h2&gt;

&lt;p&gt;Today's web is full of dirt. Most sites are full of trackers, ads, and lots of other nasty stuff penalizing websites' loading. To avoid this, AdBlockers are blooming. They offer a quick and simple solution (most of the time, a browser extension) that blocks most of the unwanted content.&lt;/p&gt;

&lt;p&gt;Unfortunately, as for the UX, AdBlockers don't deliver. They often increase the amount of memory and CPU cycles used by your web browser, slowing your browsing experience instead of boosting it. Some are doing better than others, and whole browsers&lt;sup id="fnref1"&gt;1&lt;/sup&gt; have been conceived over the idea of blocking unwanted content, and are doing an incredible job. But the web is not confined to your browser, is it?&lt;/p&gt;

&lt;p&gt;The Web is requested from everywhere in your computer. Most mainstream applications are as crammed with trackers as your next media website. Sometimes, you can even see the ads displayed in your UI (&lt;em&gt;Hello, Skype. Yes, I'm talking about you, you naughty boy&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;The AdBlockers can't do anything about that. But a simple hosts file does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosts… what?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The computer file &lt;strong&gt;hosts&lt;/strong&gt; is an operating system file that maps hostnames to IP addresses. It is a plain text file.&lt;br&gt;
&lt;cite&gt;"&lt;a href="https://en.wikipedia.org/wiki/Hosts_%28file%29" rel="noopener noreferrer"&gt;hosts (file)&lt;/a&gt;", on Wikipedia&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whenever your browser interacts with a website, it actually requests a server, located through its IP address, like 185.31.40.11 (IPv4) or 2a00:b6e0:1:20:2::1 (IPv6). It's pretty similar to a postal address.&lt;/p&gt;

&lt;p&gt;Now think about accessing a webpage, like &lt;a href="https://borisschapira.com" rel="noopener noreferrer"&gt;https://borisschapira.com&lt;/a&gt;. How does your browser know which IP address to contact? Well, the browser simply asks the Internet phone book. At least, one of them. And the phone book, called a DNS, resolves the IP address for the browser.&lt;/p&gt;

&lt;p&gt;I don’t know about you, but I never use a phone book. Most of the time, I’ve collected the address of the people to whom I want to write in my personal address book. That’s the &lt;strong&gt;hosts file&lt;/strong&gt; for you. Every time a process on your computer needs to access a resource on the Internet, it first goes through the hosts file to find out where to find it.&lt;/p&gt;

&lt;p&gt;Now, let’s say that you don’t want this process to find the resource on the badthings.com domain. &lt;em&gt;Easy peasy&lt;/em&gt;, throw it on the wrong track by associating the badthings.com domain to an unspecified address like 0.0.0.0.&lt;/p&gt;

&lt;p&gt;So basically, if someone makes a list of all the domains where bad things happen, we can redirect them all to 0.0.0.0 in our hosts file, and make &lt;strong&gt;our own Web&lt;/strong&gt; a much cooler place.&lt;/p&gt;

&lt;h2&gt;
  
  
  One project to gather them all
&lt;/h2&gt;

&lt;p&gt;There is nothing new in what I am describing here. Cool people have been doing this for years, sharing their host files. Fake news websites, gaming platforms, pornographic hubs, encryption pages, fraud attempts, and scams are all patiently identified and listed in open access files.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://github.com/StevenBlack/hosts" rel="noopener noreferrer"&gt;Steven Black's "hosts" project&lt;/a&gt;, a python script, to cram them into &lt;a href="https://raw.githubusercontent.com/borisschapira/hosts/master/hosts" rel="noopener noreferrer"&gt;a single 2MB hosts file&lt;/a&gt; containing more than 70k domains. In case you're wondering, I can and do alter the result with my own whitelist (otherwise blocked domains whose requests I don't want to prevent) and redirections (which allows me to write this article and check the result on &lt;a href="https://borisschapira-dev.com:10443/" rel="noopener noreferrer"&gt;https://borisschapira-dev.com:10443/&lt;/a&gt;, which actually points to my own machine).&lt;/p&gt;

&lt;p&gt;If you're not familiar with the command line and use Windows 10, the &lt;a href="http://www.abelhadigital.com/hostsman/" rel="noopener noreferrer"&gt;hostsman&lt;/a&gt; app will help you achieve the same goal (&lt;em&gt;unfortunately, as I just published the post, the website looks down. Fortunately, &lt;a href="https://portapps.github.io/app/hostsman-portable/" rel="noopener noreferrer"&gt;a portable version exists&lt;/a&gt;&lt;/em&gt;). I will not recommend modifying your host file on previous versions of Windows even if &lt;a href="https://borisschapira.com/2015/08/de-windows-a-mac/" rel="noopener noreferrer"&gt;I did it, before 2015 (FR)&lt;/a&gt;, unless you like to run &lt;code&gt;ipconfig /flushdns&lt;/code&gt; every 30 minutes. On Linux, I've heard people talk about using &lt;a href="https://github.com/jedisct1/dnscrypt-proxy" rel="noopener noreferrer"&gt;dnscrypt-proxy&lt;/a&gt;… but I've never tried myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv41g5sy33nj4uofgk80e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv41g5sy33nj4uofgk80e.png" alt="A screencapture from hostsman sources manager" width="578" height="436"&gt;&lt;/a&gt;&lt;/p&gt;
You can manage Update Sources in hostsman



&lt;h2&gt;
  
  
  Some tips from my daily life
&lt;/h2&gt;

&lt;p&gt;Sometimes, I need to temporaly disable this hosts file. For example, when I need to help &lt;a href="https://www.dareboost.com/" rel="noopener noreferrer"&gt;Dareboost&lt;/a&gt; clients understand the impact of third-party scripts on their pages (thus, I need to load these 3ps myself).&lt;/p&gt;

&lt;p&gt;To enable or disable my hosts file, I use a command line function that I've develop and put in my &lt;code&gt;~/.profile&lt;/code&gt; file&lt;sup id="fnref2"&gt;2&lt;/sup&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;togglehost&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; /etc/host.bak &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;sudo mv&lt;/span&gt; /etc/host.bak /etc/hosts
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hosts file is active again"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;sudo mv&lt;/span&gt; /etc/hosts /etc/host.bak
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hosts file is set aside"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this function is loaded, activating or deactivating my hosts file is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;togglehost
&lt;span class="go"&gt;Hosts file is set aside
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;togglehost
&lt;span class="go"&gt;Hosts file is active again
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But as I sometimes forget to put it back in place, I have set up a routine that checks every minute that the file is in place and, if it is not the case, warns me by using Jaime Piña's &lt;a href="https://github.com/variadico/noti" rel="noopener noreferrer"&gt;noti&lt;/a&gt; to trigger a notification. To perform this regular check, I use &lt;code&gt;crontab&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * * if [ ! -e /etc/hosts ]; then /usr/local/bin/noti -t "Host file" -m "does not exists"; fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have been using this technique for years now and, sometimes, I forget that my hosts file protects me so much. Whenever I need to use someone else's computer, or temporarily disable my hosts file, I realize the level of comfort it provides me.&lt;/p&gt;

&lt;p&gt;I'm well aware that tweaking its own hosts file is a good but technical solution. It doesn't completely replace an AdBlocker (or I haven't aggregated enough files yet) but it's an incredible performance gain, which I highly recommend for everyday browsing.&lt;/p&gt;

&lt;p&gt;Try it for yourself, and tell me what you think!&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hosts files are your computer internal address books that guide Web requests to the right servers. Fill your hosts file with domains pointing to nothingness, and those requests will quickly and surely fail. People are sharing their hosts file for years. Solutions now exist to concatenate them, and crowdsource a solution to the dirty Web we've to deal with everyday.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;If you've never tested &lt;a href="https://brave.com/" rel="noopener noreferrer"&gt;Brave Browser&lt;/a&gt;, I can only encourage you to do so, and join the 4 million people that trust it to fix the web. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Actually, I put this function in my &lt;code&gt;~/.zprofile&lt;/code&gt;, as I use &lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;Oh My ZSH&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webperf</category>
      <category>tools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>[Dogfooding] How Dareboost has benefited from Custom Timings</title>
      <dc:creator>Boris Schapira</dc:creator>
      <pubDate>Mon, 28 May 2018 14:44:34 +0000</pubDate>
      <link>https://dev.to/borisschapira/dogfooding-how-dareboost-has-benefited-from-customtimings-1cnl</link>
      <guid>https://dev.to/borisschapira/dogfooding-how-dareboost-has-benefited-from-customtimings-1cnl</guid>
      <description>&lt;p&gt;&lt;em&gt;We may be Web Performance experts, we still don’t have superpowers. We also need tools to analyze our sites and applications. So when we released our new Custom Timings feature, we naturally jumped at the chance to test it on Dareboost.com… and immediately saw the benefit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjootd2d36rvup0q3xtg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjootd2d36rvup0q3xtg7.png" alt="The Dareboost web application" width="600" height="318"&gt;&lt;/a&gt;&lt;/p&gt;
The Dareboost web application



&lt;p&gt;A few weeks ago, we have introduced a new feature in your page analysis reports and monitors: &lt;a href="https://blog.dareboost.com/en/2018/05/custom-timings-monitoring/" rel="noopener noreferrer"&gt;Custom Timings&lt;/a&gt;, tailor-made markers, to be placed in JavaScript using the User Timing API, that you can then display in Dareboost to visualize their evolution over time.&lt;/p&gt;

&lt;p&gt;We’ve chosen to prioritize this feature within our backlog because we were deeply convinced that it would allow our customers to better understand their websites performance. In fact, using it is so simple that we immediately found a practical application to meet our own needs!&lt;/p&gt;

&lt;p&gt;To explain this, let’s take a look under Dareboost’s hood first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dareboost: an AngularJS application personalized according to the current user’s rights
&lt;/h2&gt;

&lt;p&gt;Any visitor consulting &lt;a href="https://www.dareboost.com/" rel="noopener noreferrer"&gt;Dareboost website&lt;/a&gt; uses a real Web Application. In other words, the user’s browser loads JavaScript code that, once executed, takes over the browsing experience and emulates the behaviour of an application instead of the navigation between multiple web pages. For example, a user can switch from one screen to another without reloading the side menu.&lt;/p&gt;

&lt;p&gt;To ensure this applicative behaviour in a web page, known as SPA (for Single Page Application), we use a JavaScript framework: AngularJS. This framework performs the customization operations, using an XHR request (XMLHttpRequest) to retrieve the user’s context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two shakes of a lamb’s tail
&lt;/h2&gt;

&lt;p&gt;We decided to set up several Custom Timings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When AngularJS begins its bootstrapping: &lt;code&gt;angular_boostrap_start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  When AngularJS is bootstrapped (and starts doing what we want him to do to present Dareboost’s interface): &lt;code&gt;angular_boostrap_end&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  When we ask Angular to fetch the current user’s context: &lt;code&gt;userinfo_xhr_start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  When the context is effectively recovered: &lt;code&gt;userinfo_xhr_stop&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  When the content is displayed in the main area: &lt;code&gt;view_content_loaded&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setting up these marks is so simple that some customers ask us if these are really the only actions to take. Check it by yourself: once you have found which portion of code corresponds to the behavior you want to monitor, just add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;performance.mark("angular_boostrap_start");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We really had nothing more to do for Dareboost to start collecting these new data: no particular configuration, no declaration, or anything else. A few days later, we consulted our monitoring data and the data were available. We didn’t expect such results*!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56vm7hrsnzl3ipwzd54p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56vm7hrsnzl3ipwzd54p.png" alt="Erratic timings for the userinfo_xhr_stop mark" width="600" height="356"&gt;&lt;/a&gt;&lt;/p&gt;
Erratic timings for the `userinfo_xhr_stop` mark



&lt;p&gt;* In fact, we did, because we already had experienced slowdowns several times, in a significant way. But seeing them on a plot is something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elementary, my dear Watson!
&lt;/h2&gt;

&lt;p&gt;What’s going on? The AngularJS booting phase, marked by the events &lt;code&gt;angular_bootstrap_start&lt;/code&gt; and &lt;code&gt;angular_bootstrap_end&lt;/code&gt;, is quite obvious. But, surprisingly, we find the context request in the middle. Actually, this is only fair: the context request and loading of AngularJS are asynchronous but, in reality, depend on each other. Indeed, the request must wait until AngularJS is loaded to be initiated. If we want a finer follow-up of this request, we will surely need to move this marker so that it better meets its purpose.&lt;/p&gt;

&lt;p&gt;The Custom Timing of the main area comes next, which is reassuring in Dareboost’s ability to respond quickly to user demand, since it is mainly on this area that he looks at.&lt;/p&gt;

&lt;p&gt;Finally, we see the Custom Timing of the context request response, which is unsteady and bad: almost two seconds for context recovery. Two seconds of latency is quite a long delay for a busy user! Analyses that refuse to start, potentially unavailable scenarios (because they did not have the item in the menu)… we had to fix it quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2hw908yiskuncjocj89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2hw908yiskuncjocj89.png" alt="Immediate action by the development team solved the problem" width="600" height="362"&gt;&lt;/a&gt;&lt;/p&gt;
Immediate action by the development team solved the problem



&lt;p&gt;Fortunately, the team promptly identified the back-end side issues that could explain the delay. After a minor release, the situation clearly improved:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswg5nmcy47s3k6buryz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswg5nmcy47s3k6buryz2.png" alt="This is how Dareboost performs now" width="600" height="359"&gt;&lt;/a&gt;&lt;/p&gt;
This is how Dareboost performs now



&lt;p&gt;The situation has returned to a normal behaviour, with the main contents appearing simultaneously with the determination of the user context.&lt;/p&gt;

&lt;h2&gt;
  
  
  In a nutshell
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Setting up Custom Timings takes a few seconds&lt;/strong&gt; and does not require any special configuration in Dareboost&lt;/li&gt;
&lt;li&gt;  Custom Timings are new indicators to &lt;strong&gt;understand what was invisible before&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  Custom Timings are particularly suitable for &lt;strong&gt;monitoring the performance of SPAs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  The shoemaker’s children don’t always go barefoot!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>monitoring</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
