What are the Core Web Vitals?

The Core Web Vitals are three metrics that Google uses to measure the performance of your website or webshop. Those are:

  • Page speed
  • Interactivity
  • Visual stability

Page speed - LCP

Largest Contentful Paint (LCP) is the first metric of the Core Web Vitals. This metric is used to measure the page speed. Long story short: how long it takes before the largest image or text block, which is visible above the fold, is fully visible.

Interactivity - FID

First Input Delay (FID), the second metric of the Core Web Vitals, is the delay between the first interaction from the visitors and when the web page actually responds. Pressing a button to open the navigation menu, for instance.

Visual stability - CLS

Cumulative Layout Shift (CLS), the third metric of the Core Web Vitals, is a sum of all the shifts that happen on a web page. Did you ever experience an advert suddenly appearing, pushing everything down, just before you want to click something? You are not alone.

Not just adverts cause this.. Images that take up space after loading, pieces of text of which their custom font suddenly loads - causing the characters to take up less or more space, CSS files that are applied way too late and having to redraw the whole web page.. these all cause the layout to shift, which is not good for the CLS score of the Core Web Vitals.

Insights in your Core Web Vitals

We briefly explain to you how you can get insights into the progress of optimizing your website or webshop for the Core Web Vitals. Since it does not fix itself by testing it over and over again, we would like to focus on solutions instead.

By using PageSpeed Insights, you will get insights into the three metrics that the Core Web Vitals are all about. You will notice that the second metric, First Input Delay, is missing in the lab data. That is because this metric originates from real world data (from users that opted in to sharing data with Google in order to improve their experience).

You can recognize the Core Web Vitals metrics by their blue ribbon behind the name of the metric. Your score for each metric is divided into three ranges with each their own color and shape (for people with color blindness):

  • Red triangle - Poor
    • LCP > 4s
    • FID > 300ms
    • CLS > 0.25
  • Orange square - Needs improvement
    • LCP <= 4s
    • FID <= 300ms
    • CLS <= 0.25
  • Green circle - Good
    • LCP < 2.5s
    • FID < 100ms
    • CLS < 0.1

Low hanging fruit for the Core Web Vitals

Because of possible newcomers to optimizing for the Core Web Vitals, we decided to start with solutions that are easier to implement. Have you read articles about optimizing for the Core Web Vitals before? If so, please scan this chapter to see if there is any low hanging fruit for you left over, and then scroll/swipe down to the unique solutions that we are giving away in this article to help you with your Core Web Vitals optimization.

Lazy loading images and inline frames

If you are using WordPress, and you have kept the system up-to-date, then WordPress has already enabled lazy loading for you. Are you using a different system? Well then, you can enable lazy loading for images by adding HTML loading="lazy" all <img>-tags and <iframe>-tags. This is an attribute that is introduced in 2019 in order to make lazy loading happen by web browsers, instead of by using JavaScript. At this moment (may 2021), this so called native lazy-loading, is supported by the modern web browsers.

Safari and Safari on iOS do not have this feature enabled by default; the user has to enable this feature manually. This means that developers are encouraged to use JavaScript-based lazy loading as a fallback for the Safari web browser. We hope that Safari enables the lazy loading feature soon by default, so there are no JavaScript-based solutions are required for modern web browsers. That would also make the Core Web Vitals optimization a little bit easier.

WebP-images for a faster download

WebP is an encoding for images, which maked them 39% lighter (on average) than JPEG images and 45% lighter than PNG images. Web pages with a lot of heavy images will not meet the Core Web Vitals if visitors have a lower downloading speed.

Are you using WordPress? If so, you can use WebP Express. To use this plugin, install it, activate it, go to WordPress' backend, place your mouse at Settings and click WebP Express. Then you scroll down to the section called Alter HTML

Copy the settings shown in Figure 1 regarding section Alter HTML.

Alter HTML setting WebP Express

Figure 1. Alter HTML settings for plugin WebP Express

If you copied these settings, the plugin will show WebP images instead of JPEG images and PNG images. If a web browser does not support WebP images, then it will serve the JPEG or PNG images instead. You can also choose to check the box Replace image URLs, since all modern web browsers support WebP.

Microsoft Internet Explorer does not support WebP images, but luckily almost nobody ever uses that web browser anymore. If your target audience does use Internet Explorer, then I suggest to copy the settings from Figure 1 and check the box Dynamically load picturefill.js on older browsers, since the <picture>-tag is not supported by IE.

You can convert all images by pressing button Bulk Convert.

Optimizing images is a great step in the right direction for your Core Web Vitals optimization.

Minifying JavaScript files

Eventhough this only reduces the size of JavaScript files, many websites can get a boost from this. Users with a slower internet connection won't have to wait as long. Step by step you will get closer to meeting the Core Web Vitals. Many optimizations are needed, of which none are decisive on their own.

In case you do not yet use a WordPress plugin for page speed optimization, I suggest using a plugin called LiteSpeed Cache. After you have installed LiteSpeed Cache, go to the backend of WordPress, place your mouse at LiteSpeed Cache in the side menu and then click Page Optimization. Now click tab [2] JS Settings and enable JS Minify. Now click the blue button Save Changes. Check if everything still works!

Combining JavaScript files

As discussed above, you can use the WordPress plugin LiteSpeed Cache to perform all sorts of optimizations. Go to the backend of WordPress, place your mouse at LiteSpeed Cache and click Page Optimization. Again, click tab [2] JS Settings and check box JS Combine. Now click the blue button Save Changes. Again, check if everything still works! It is absolutely not okay if the functionality of your website of webshop needs to be limited in order to meet the Core Web Vitals.

Pushing JavaScript files

By using the LiteSpeed Cache plugin, via Page Optimization you click tab [2] JS Settings and then enable option JS HTTP/2 Push. You can only use this function if your website uses HTTPS with a valid SSL certificate.

Although HTTPS is not related to the Core Web Vitals, it is a must-have to be able to rank in the search results with a webshop.

Minifying CSS files

The same story goes for minifying CSS files. Within the backend of WordPress, click Page Optimization and enable option CSS Minify. Save the changes again and check if everything works and looks good. At the end of your Core Web Vitals optimization it is the intention that everything still works fine. In fact, it should work even better and faster!

Combining CSS files

On the same page, enable option CSS Combine, save changes, and check if everything looks good and still works.

Pushing CSS files

On that same page, enable option CSS HTTP/2 Push. This will only work if your website or webshop used HTTPS and has a valid SSL certificate. Save the changes. Check if, after enabling this option, if this benefits your page speed.

Minify HTML

By using WordPress plugin LiteSpeed Cache, via Page Optimization click tab [3] Optimization and then enable option HTML Minify. Save changes and check if your website looks good and if there are any JavaScript errors that weren't there before minifying the HTML.

Unique solutions

In order to be able to meet the Core Web Vitals, you sometimes need a little more than all the low hanging fruit that gets repeated on every blog post. It requires help from someone with experience in building websites and webshops, but that person should also know how to optimize the page speed and user experience of websites and webshops. That is what the Core Web Vitals are all about.

Lowering the amount of requests

Before files can be downloaded, your device needs to send a request to the website's server that stores the file. How long it takes before a device can start downloading a file stored on a server, is called Time To First Byte (TTFB). Imagine that it takes 50 milliseconds for a single request and that a device needs to download 45 files to complete a web page, then that would cost more than 2 seconds in theory. In practice a device sends multiple requests at a time, which makes this take less time. Regardless, it has a significant influence on the page loading time, and thereby a direct influence on whether or not your website or webshop will meet the Core Web Vitals.

Imagine, a device requests a CSS file from a server in order to color the characters on a web page, setting font sizes, line height, and so on. It takes 50 milliseconds before your device gets a response and can start downloading the file.

Now it takes another 50 milliseconds to download the file. Nothing terrible has happened yet. Until your device realizes that the CSS file wants to change the font of the web page for which it needs two font files, one meant for bold text, and the other for normal text.

This is inefficient, because the device now has to make a request for each of those two font files. It would have beem more efficient if those two font files were already inside of the CSS file, because now, after 100 milliseconds, the device realizes that it needs to wait another 100 milliseconds for those two requests together. These requests could have been made beforehand, so the browser could have waited for the two font files together with the CSS file at the same time. That would have taken half of the time that is spent by this inefficient way of requesting resources.

Downloading files beforehand is called preloading. This is something we will cover further down in this article, since that is a technique which is sometimes required to prevent layout shifts in some cases. Layout shifts cause a high CLS score, which is the third metric of the Core Web Vitals.

Data URI for small favicons

A favicon is a miniature version of your logo that is used in the tabs in your seb browser. See Figure 2. These favicons are also visible im mobile search results in Google. Since favicons are often just 1KB in size, it is more efficient to place their file's content directly into the HTML document. That way your device does not need to send a seperate request for a file that is 1KB in size. If a file is way bigger, let's say 200KB, then it is rrcommended to just let it be a seperate request. That is because files downloaded through requests can get cached by your web browser. This way it does not need to download the file for a request that your device has already done before if you open a different lage on the same website.

The favicon is easy to miss, as it is just a little icon. Regardless of how small a file may be, it still takes another request to be able to download it. It is the intention to lower the amount of requests needed for your web pages to load. Every additional request that you are able to cut down on, no matter how small the file is? is a step closer to meeting the Core Web Vitals.

Favicon in a web browser tab

Figure 2. Favicon in web browser tab

On our website we use a data URI for the 32x32 favicon, since that size is the most commonly used along favicons. The larger favicons are dealt with through a seperate request, since these are not used as often and are generally heavier in file size.

You can generate a data URI for your smallest favicon, by using the Image to Data URI converter. See Figure 3 for an example of how a data URI can be used for a favicon.

Favicon data URI for Core Web Vitals optimization

Figure 3. Example of a data URI for a favicon

Data URI for woff2 fonts

Coming back to the example of the CSS file that caused two seperate requests to be done for font files.. It is possible to insert the complete font file into the CSS file, so the device does not need to send two seperate requests for them.

However, it is recommended that you only do this for font files that you are sure of will get used, as the size of the CSS file will increase because the font files are litteraly inside it. On our website, we use icons that are inside of a font file. That font file was very small and was requested by a CSS file, so we decided to put the font file inside of the CSS file, to cut down on requests. See Figure 4.

woff2 data URI for Core Web Vitals optimization

Figure 4. Data URI for a woff2 font file

You can generate a data URI for woff2 files yourself using the data: URI Generator. Make sure to select option Explicitly specify mime type and then enter font/woff2 in the field labeled Enter Mime Type. See Figure 5.

Now click the button Generate Data URI and copy it (CTRL + C). You can now replace the URL of the woff2 file by the data URI that you just copied by selecting it and pasting (CTRL + V).

Make sure that you replace the correct URL - search for the URL before format('woff2') and between url(' and ').

Data URI Mime Type to optimize for Core Web Vitals

Figure 5. Specifying the Mime Type for which the data URI is supposed to be

Asynchrononous decoding of images

When an image is downloaded, it can not yet be displayed. First it needs to be converted into pixels to be drawn on the screen. Converting image files into pixels is what's called decoding images. Converting pixels into an image file is called encoding.

The time that is costs to decode an image depends on the size of the file, how powerful the CPU is, amount of RAM of the device, and the encoding of the image (JPEG, PNG, WebpP, AVIF). To give you an impression of how much time it takes: on a relatively fast PC it takes 24 milliseconds to decode a JPEG image that weighs 119KB (dimensions: 2480x1651). This would take longer on mobile devices that have a slower CPU and less RAM. On those devices this can take 100 milliseconds or longer. The size of an image does not only affect the download time, but also how long it takes for your web browser to draw it on your screen.

By default, decoding images will block the process of drawing other content on a web page, but it is possible to asynchronously decode image by using an HTML attribute called decoding.

The default value for this attribute is auto. In that case the web browser will decide for itsself what the best strategy is for decoding the image. Value sync tells the web browser to draw the image synchronously with the other content of the web page. Using value async will give you the ability to decode the image asynchronously, so it does not block the process of drawing the rest.

Wikipedia does not want that decoding the images delays the presentation of the rest of the content on their web pages. That's why they chose to asynchronously decode the images, to give priority to the textual content. See Figure 6.

Asynchronous decoding with Wikipedia.org as an example

Figure 6. Wikipedia.org using asynchronous decoding of images

Disabling JavaScript polyfills

JavaScript polyfills serve functionalities that are not offered by outdated web browsers, such as Microsoft Internet Explorer. The reason why you can consider disabling polyfills, is to favor the speed of your website to come closer to meeting the Core Web Vitals. The difference in page speed may seem small, but if you sum up all the optimizations it will have a great impact.

Globally, Internet Explorer only has a market share of 0.81% (February 2021). So you can choose to disable the polyfill, may your target audience not use Internet Explorer. Internet Explorer may still be in use by the older generation, because some elderly people may not even know what a web browser is, or don't know that their web browser is outdated, or they don't know how to install modern web browsers, such as Google Chrome, Microsoft Edge, and Mozilla Firefox.

Basically, what you can do is sacrifice some cross browser compatibility to offer a better experience on modern web browsers. Staying up to date with all the new features that the modern web has to offer, is an important part of optimizing for the Core Web Vitals and for page speed in general, because there are more efficient encodings for images, videos, and fonts.

Do you use WordPress, by any chance? If so, you can consider disabling Babel's polyfill. Before you do this, however, you should check whether or not your website or webshop has this polyfill enabled. If you are using a WordPress plugin for page speed optimization, please consider disabling that plugin temporarily to prevent files from being combined and renamed.

Open a page in your website or webshop, press F12 (Mac: Command + Option + I), then press CTRL + F, type wp-polyfill-js, and press Enter. If nothing is found, then your website probably does not have this polyfill enabled.

If your website does use this polyfill, then you can disable this polyfill by adding the following code to your child theme in the file called functions.php:

function tw_remove_wp_polyfill() {
add_action('wp_enqueue_scripts', 'tw_remove_wp_polyfill');

If you do not have a child theme, then you can generate a child theme using this plugin: Child Theme Generator. We recommend creating a backup of your WordPress website (database and files) before activating the child theme, since we have once experienced a theme saving the theme options incorrectly while using a child theme.

Do you have no access to FTP for your WordPress website, but does Appearance inside of the side menu in the backend of WordPress contain a link called Theme Editor ? Then you can click that link. Then switch over to the child theme by using the select box on top of the right sidebar). Then click Theme Functions (functions.php) in the right sidebar. Now copy and paste the above code in in the end of the file. Now press the blue button Update File.

If you do have access to FTP, then you can find the file by opening the folder called wp-content (after opening the WordPress' root folder, which is called either public_html or www or simply the name of your website), then open folder themes, and then open the folder that has -child appended to the name of the theme that your website currently uses. Copy and paste the code above to the end of the file called functions.php and save it.

Be sure to check if everything works! Open a few pages, press F12 (Mac: Command + Option + I) on each of them, click tab Console and check for JavaScript errors. Are there any errors? If so, be sure to check whether these errors are caused by disabling the polyfill (remove the code you added in file functions.php). If the errors were caused by removing the polyfill, then keep the polyfill.

In case you disabled a plugin that served for page speed optimization, then be sure to enable that plugin again. That would not be good for the progress of your Core Web Vitals optimization, obviously.

Splitting up CSS files into device specific CSS files

In case you have written a lot of CSS by yourself for your website, then consider bundling those CSS files (in the same order as they are loaded in the DOM) and then split it up into three different CSS files:

  • a file that has no media queries;
  • a file with only media queries for mobile devices (smartphones and tablets);
  • a file that contains media queries only for laptops and desktops.

Be aware: if your website used HTML output caching, then be sure to check whether that tool has an option to keep a seperate cache for mobile devices, since otherwise only the CSS file for laptops and desktops will get enqueued on mobile devices as it is cached after opening the web page on a desktop device (the same can happen the other way around). If this is not possible, then I suggest not splitting up your CSS files into device specific files.

Please, keep a backup of your original CSS files. You can use user-agent sniffing in PHP, or in any other backend language, to find out whether to enqueue the CSS file for mobile devices or for laptops and desktops. This way you can enqueue files that contain only the media queries that can match up with the viewport widths for mobile devices and laptops or desktops. You should then use JavaScript as a reliable way to back it up by checking the viewport width of the device (which is not possible by using backend languages, as such data is not transfered through requests to your server, sadly).

The more CSS that has to be processed and applied, the more time it costs for the web browser to draw/render the web page. Less CSS is better for the thirth metric of the Core Web Vitals: Largest Contentful Paint (LCP).

Removing unused JavaScript and CSS

JavaScript can really slow down a page, especially when there is a lot of it. So it's best to remove the JavaScript that is not used. The same story is true for CSS files. I've discussed how to remove unused CSS automatically.

Preloading important CSS in the <head>

If the most important CSS file gets downloaded after other files, then that can cause a period where the web browser may have already drawn the web page before the most important CSS file was downloaded, thus not being applied yet. This looks ugly and it is bad for your CLS-score, since it also causes huge layout shifts.

High CLS scores mean bad visual stability (#3 of the Core Web Vitals). Simply moving the most important CSS file all the way to the top of the <head> will enable your the rules in your CSS file to be overwritten by CSS files that would then get applied after your most important CSS file. That is not good, by the way.

You can, however, tell the web browser to download the most important CSS file in advance, but that the priority of the CSS file is depending on the position of the <link>-tag that references that very CSS file. This will minimize the chance that web browsers will draw your web page before applying the most important CSS file because of downloading it too late. See Figure 7.

Preloading important CSS to optimize for Core Web Vitals

Figure 7. Preloading the most important CSS file in the <head>

Lazy rendering

Lazy rendering for Core Web Vitals optimization

Figure 8. The last section is outside of the viewport and is not yet drawn/rendered

When you open a web page, your web browser will use the CSS files to style the HTML document. The larger the CSS file, the more elements will be affected by the file, causing the web browser to need more time to draw the web page.

Your web browser draws the whole web page, regardless of whether or not all sections will enter your viewport at some point when scrolling down the page. It is possible to tell your web browser to only draw the part of the web page that is visible inside of your viewport (with a threshold of 50%). This will safe your web browser time when drawing the web page.

It is the same idea as lazy loading images, meaning that the web browser only loads images that enter the viewport (with a threshold as well). See Figure 8 for a visualization.

Applying lazy rendering is easy, but it also brings some problems along with it - when a section is not rendered by the web browser, then it does not have a height.

This will cause the web page to look shorter, because the scrollbar's thumb is bigger (indicating that the page is shorter), because of all the sections that are 0 pixels high.

When a visitor then scrolls down, the other sections will enter the lazy rendering threshold and will get rendered, taking up space accordingly. This will cause the scrollbar's thumb to go bananas. To prevent this, the sections need an estimated height that you have to provide by yourself. See Figure 9.

However, those estimations need to be pretty accurate in order to offer a seemless experience. It also needs other fixes.

Accurate estimation of height for lazy rendering

Figure 9. Accuracy of automatic estimation of the height for lazy rendering

Do you want to provide an automatic estimation for the height of sections? Then be sure to check out our blog post about calculating contain-intrinsic-size for content-visibility, which covers this in as much detail as possible.