Fix "Avoid Chaining Critical Requests" in Lighthouse.

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

"Avoid Chaining Critical Requests" in short

Critical requests are network requests that are fetched by the browser with a high priority.

When a page or a script causes multiple resources to be downloaded with high priority, we speak of a chain of critical requests.

A browser will not (fully) start rendering and painting the page until all of these critical resources have been downloaded. Any critical resource can therefore block the first rendering of a page. The larger or heavier the Critical Request Chain becomes, the more influence the Critical Request Chain has on the loading time of the page according to lighthouse.

Critical request chain example

How the download priority is determined

Critical requests are the resources that are downloaded with high priority during initial page load. How is this priority determined?

The download priority is determined by the browser itself. The browser follows a set of rules to determine the priority of each asset. Which elements ultimately receive the highest priority depends on the structure of the page. The elements that your browser thinks are necessary for the first rendering of the page are given the highest priority.

Your browser initially makes an educated guess at which elements are most important. Generally speaking, the download priority works like this: HTML always takes the highest priority, then Style sheets, synchronous JavaScript, Fonts, Ajax Requests, images at the top of the page, images later on the page, and then asynchronous JavaScripts.

You can see for yourself which sources are given high priority on your page. Open the dev-console with Ctrl + Shift + J. Navigate to the network tab, right click on the column names and select 'Priority'

Dev Console Resouce Priority

How does the critical Request Chain affect the page load time?

When loading a page, a browser starts in 'display blocking' mode. In this mode, the most important sources are downloaded with high priority. Those are the critical resources.

A browser will not (fully) start rendering the page until all critical resources have been downloaded. So any critical resource can block the first rendering of a page.

The fewer critical resources a page has, the less work the browser has to do to get the first content on the screen, and the less competition there is for the CPU and other resources.

How to fix "Avoid Chaining Critical Requests" in lighthouse?

You can reduce the impact of critical requests in three ways:

  1. Reduce the number of critical resources . Convert critical resources to non-critical resources by removing or defering them.
  2. Reduce the number of critical bytes . It may be obvious, but reducing the number of bytes of the critical path resources makes the critical resources download faster. For example through gzip compression, javascript tree shaking, image optimization or font subsetting.
  3. Improve the download order of the critical path . Use resource hints such as preloading to skip resource discovery and to ensure that the critical resources are downloaded as quickly as possible.

There are many options. Which option is the best one depends on the file type of the resource:

1. HTML

The HTML, which is actually the page you are visiting, is always downloaded with the highest priority. The page itself is always part of the critical request chain. That's why the page itself is the first thing to consider when optimizing the critical request chain..

Delayed loading of content: Many large sites, such as Google itself, use this technique to reduce the critical request chain. On the search results page, for example, parts of the content, which are not immediately needed, are only loaded later via an AJAX request.

Minify: Smaller is always faster, use html minification to remove comments, spaces and blank lines from the page.

Compression : Finally, it is important to properly compress stylesheets with Brotli or GZIP compression

2. Stylesheets

Stylesheets in the head of the page are always critical. Without styles, a browser does not know what the page will look like. Stylesheets are therefore a standard part of the critical request chain in lighthouse.

Critical CSS: Stylesheets can be made non-critical with a simple trick where the stylesheet is preloaded through resource hints and added as a stylesheet after preloading has finished.
Add the following code on the page: Your browser will now download the stylesheet at a lower priority and threat the CSS and non-render blocking. It will start rendering without waiting for the CSS.

<link rel="preload"
      href="css.css"
      type="text/css"
      as="style"
      onload="this.onload=null;this.rel='stylesheet';"/>

Watch as something strange now happenings on the page. First the page is shown and only after loading the CSS the styling is applied. All content will now flash from unstyled content to styled content. We can fix this with critical CSS.
Critical CSS is a collection of all the CSS rules you need for the visible part of the page. You can generate critical CSS yourself through NodeJS or through a number of online tools. Place this critical CSS in the head of the page and load the rest of the CSS at a lower priority.

Media queries : Load only the styles for your device. Your page is often visited on mobile. So you don't actually have to download the styles for Desktop and Print. This saves time and thus shortens the critical request chain in the lighthouse.

Use the media attribute. The media attribute ensures that a stage is only downloaded if the media from the home does not match the media you are currently using.

<link href="all.css" rel="stylesheet" media="all">
<link href="print.css" rel="stylesheet" media="print">
<link href="desktop.css" rel="stylesheet" media="screen and (min-device-width: 1024px)">

Minify: Remove unused CSS. Many sites use CSS libraries such as bootstrap. These libraries are often over-complete and not all style declarations are used.
It is easy to edit these libraries via a CSS preprocessor (such as SASS ). Simply rewmove the unused style groups by chanding what should be included to make them a lot smaller. These preprocessors also give you the option to minify your CSS by removing all spaces and newlines.
">

Compression : Finally, it is important that to properly compress stylesheets with Brotli or GZIP compression

3. Javascript

Javascript files in the head of the page are downloaded with a high priority by default and block the rendering of the page while they are being downloaded and executed. Javascript is therefore a standard part of the critical request chain.

Defer and Async : Adjust the priority of the Javascript files by loading them asynchronously through the async or defer attribute. Asynchronous script files are downloaded in parallel with a lower priority. Deferred JavaScript are also loaded in parallell and the execution of the Javascript file is delayed so that Javascript execution also does not block the initial loading of the page.

// blocks loading and execution
<script src="normalscript.js">
// async does not block during load, but it does block during execution
<script async src="asyncscript.js">
// defer does not block both during load nor execution
<script defer src="deferscript.js">

Code splitting and preloading: If the page does not allow JavaScript to load asynchronously, it might be a good idea to split JavaScript into multiple files. Place the part of the JavaScript that is critical during page load in a small file and preload this file. Place the non-critical javascript in another file and let it load and run deferred or async.

Minify : Shrink the number of bytes in two ways through a Javascript Uglyfier tool. This is a smart tool that analyzes Javascript and makes it as small as possible. ">

Compression : In addition, reduce the number of bytes by compressing Javascript via Gzip or Brotli.

4. WebFonts

Web fonts are usually loaded last files in the critical request chain. This is because web fonts rely on discovery. They are only loaded when a browser finds out that they are needed. For this, a browser must first analyze the HTML and look up in the style sheet which font is used.

Preloading : When you are sure that you are going to rely on a font, it is usually faster to preload this font. The font is then downloaded as early as possible, this minumizes the influence on the critical request chain. Preload a font by adding this code as early as possible in the head of the page

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
Font strategy : In addition, there are many other ways to make fonts load faster.
  • Always rely on local web fonts and never remotely hosted fonts like Google fonts.
  • Resize the font with font subsetting
  • Loead non-critical fonts thouregh the the Javascript <a href="https://developer.mozilla.org/en-US/docs/Web/API/FontFace">fontface interface</a>
  • Use display = swap to avoid font from blocking the initial rendering
  • Let browsers generate their own font variants through font synthesis

Images

Images that appear in the visible viewport during page load can also be given a high priority and can interfear with the critical path. When you are sure that an image will always appear in the visible part of the website, it can be useful to preload this image as well.

<link rel="preload" as="image" href="important-image.webp">

For All images that are not immediately visible, err on the side of caution and lazy load these images. Use loading = "lazy" to delay loading the image until just before the image becomes visible.

<img loading="lazy" src="lazy-image.webp" width="20" height="20" alt="...">

5. AJAX Request

Ajax requests are allways assinged a high priorit. Therefore, preferably postpone Ajax requests until the page has finished rendering. Wait until the page has sent the "load" event.

If it is not possible to postpone the AJAX request, you can ensure that the Ajax request available to the browser by preloading it.

window.addEventListener('load', (event)=>{
  console.log('this is a good time for an AJAX request');
});

6. iframes

Iframes are usually downloaded at a high priority. Because an iframe is actually a page withinin a page an iframe can cause a very significant delay n pag eloading times. The resources that the iframe requires may also be downloaded at high priority and form its own critical request chain. The use of iframes can therefore significantly affect your lighthouse score.

You can delay loading an iframe via the loading = "lazy" attribute. That often makes a difference when the iframe is not immediately visible during loading. It is often faster to inject that iframe into the page through JavaScript. This allows you more control over the timing to be sure that it does not end up in the critical request chain.

I help teams pass the Core Web Vitals:

lighthouse 100 score

A slow website is likely to miss out on conversions and revenue. Nearly half of internet searchers don't wait three seconds for a page to load before going to another site. Ask yourself: "Is my site fast enough to convert visitors into customers?"

Fix Avoid Chaining Critical Requests in LighthouseCore Web Vitals Fix Avoid Chaining Critical Requests in Lighthouse