Vue Storefront is now Alokai! Learn More
Improving Core Web Vitals

Improving Core Web Vitals

Web Vitals are unified and simplified metrics created by Google to help site owners understand the quality of experience they are delivering to their users. Core Web Vitals are the subset of Web Vitals focused on three aspects of the user experience - loading (LCP), interactivity (INP), and visual stability (CLS).

Largest Contentful Paint (LCP)

Largest Contentful Paint (LCP) is the time it takes for the browser to paint the largest contentful element on the page. To improve the LCP metric, you need to start loading that element as fast as possible.

If it needs an asset like JavaScript, CSS, image, or font, use the "preloading". It's a technique for telling a browser to download a resource before it discovers it's needed.

For example, you might have a font that the browser can discover late (because it first needs to download and parse the CSS file), but you know that it's critical to your website. You can preload it, so once the browser parses the CSS and finds out that the font is needed, it will already have it downloaded.

Identifying the Largest Contentful Paint

The easiest way to learn which element is the Largest Contentful Paint is using PageSpeed Insights page. After generating the report, the LCP metric and what element it relies on is displayed under the "Largest Contentful Paint element" diagnostic.

Another option is to run Lighthouse in Chrome DevTools, described on Google Developers website.

Preloading Images

If there is an image in the viewport, preloading it will help the browser load it as soon as possible.

Frameworks like Next.js and Nuxt have image libraries that provide preloading functionality, but it is also possible to preload images manually using the <link rel="preload"> tag.

Next.js
https://nextjs.org/docs/pages/api-reference/components/image#priority
<Image
  src="/image.png"
  priority={true}
/>

Making Resources Smaller and Faster

If you are already preloading resources, you can also improve LCP by making the resources load faster. This will help the browser load and paint the content faster.

A few examples of this are:

  • Using the proper size image and not unnecessarily using a larger image
  • Using modern image formats
  • Reducing the web font size
  • Using a CDN to reduce the request times

See More:

Interaction to Next Paint (INP)

Interaction to Next Paint (INP) measures how long a browser's paint cycle is blocked after a user interacts with a page.

Three areas where INP can be improved are:

  1. Input Delay - the time it takes for the browser to process user input and trigger event callbacks
  2. Event Callbacks - the time it takes for the browser to execute event callbacks after user input
  3. Rendering - the time it takes for the browser to render the page after user input

We recommend reading Google's Guide on Optimizing INP to learn more about how INP is calculated and some JavaScript techniques that can help improve it.

For rendering, some common issues that can cause poor INP are:

  1. Complex CSS selectors - when a selector is too complex, the browser will have to parse and calculate the selector's specificity, which can slow down the rendering process after an interaction
  2. Large layout shifts - if an interaction causes a large layout shift, the browser will have to recalculate a large layout and then repaint the entire page, which can slow down the rendering process
  3. Large DOMs - the larger the DOM, the more expensive any rendering and updating operations will be

Tools like DebugBear's INP Debugger can help you identify the areas that need improvement.

See More:

Cumulative Layout Shift (CLS)

Cumulate Layout Shift (INP) is an important user-centric metric for measuring visual stability, which shows if page had any unexpected movement. It is a measure of stability in the layout of a page.

Some examples of things that can increase layout shifts are images, web fonts, and dynamically loaded content.

Images

When the browser parses the HTML, it will reserve the space for images based on their width and height attributes. If they are not defined - the browser will not reserve the extra space. So when the image is loaded, the image will cause the other elements on the page to shift around.

This can be avoided by setting the width and height attributes of the image. This way, even while the image is loading, the browser will account for it when it calculates the layout.

<img
  src="..."
  width="128"
  height="128"
/>

Web Fonts

If your site uses web fonts, there is a change that the browser will not have the fonts loaded when the page is first loaded. When this happens, the browser will either not show any text at all, or it will show the text in a different font. When your web font is loaded, there will be a layout shift because different fonts can have different sizes for the same characters.

One solution for this is to create a fallback font that uses the same dimensions as your loaded web font. This can be achieved through CSS font families and CSS Font Metrics

@font-face {
  font-family: 'Roboto override';
  src: local('BlinkMacSystemFont'), local('Segoe UI'), local('Helvetica Neue'),
      local('Arial'), local('Noto Sans');
  ascent-override: 92.7734375%;
  descent-override: 24.4140625%;
  line-gap-override: 0%;
}

To make this easier, there are some tools that can help you with this.

  • Fontaine - automatically generates fallback fonts for your web fonts
  • Capsize - generates CSS font metrics for your web fonts

Dynamic Content

Dynamic content can also cause layout shifts. For example, if your application has a promotional banner that is loaded asynchronously, there will be a layout shift when the banner is loaded. Another example would be if your a categories page loads the list of products asynchronously, there will be a layout shift when the products are loaded.

A good way to avoid this and improve the user experience is to reserve the space for the dynamic content while it is loading.

For product cards, this is a great use case for showing skeletons of the cards while the data is loading. This will signal to the user that something is loading, it will decrease the perceived load time, and it will reduce the layout shift.

Next.js
<Suspense
  fallback={
    <SkeletonCards />
  }
>
  <ProductCards />
</Suspense>

See More: