Cumulative Layout Shift (CLS) is a Core Web Vitals metric that calculates the visual stability of a given web page. It’s calculated by measuring all layout shift scores that happen during the entire lifespan of a page, and then choosing the group of layout shifts within a single session window (a given timespan) with the greatest total layout shift score.
A CLS score can be as low as 0 for fully static pages and gets higher the more layout shifts occur on the page.
In 2021, Cumulative Layout Shift became a Google ranking factor as part of Core Web Vitals and the Google Page Experience update.
What’s a good CLS score?
The lower your score, the more stable your layout is. Official CLS thresholds used by Google’s performance measuring tools are as follows:
- Good – CLS below 0.1,
- Needs improvement – CLS between 0.1 and 0.25,
- Poor – CLS above 0.25.
To receive a “good” CLS threshold, Google recommends that you keep your CLS score under 0.1 for 75% of all page views to a given page.
Why you should worry about Cumulative Layout Shift
CLS became a ranking factor in June 2021 when Google’s Page Experience Update started rolling out. That means your CLS score (together with Largest Contentful Paint and First Input Delay metrics) now affects your SEO. While it’s likely to be a minor ranking factor, your CLS score (along with the other Core Web Vitals) may reflect on the traffic you get from Google and other search engines.
Moreover, CLS correlates with user behavior metrics. While Google claims it doesn’t use metrics like dwell time or bounce rate for ranking purposes, other search engines, like Bing, admit to using those metrics in their ranking algorithms.
Negative effects of multiple layout shifts span from mild annoyance to even accidentally purchasing the wrong product. It can result in bad reviews for the company and discourage users from returning to the site as well as repel new clients.
Common causes for high Cumulative Layout Shift
According to Google, the most common causes of high CLS are:
- Images without dimensions provided in the source code,
- Ads, embeds, and iframes without dimensions,
- Dynamically injected content,
- Web fonts causing FOIT/FOUT (Flash of Invisible Text and Flash of Unstyled Text),
- Actions waiting for a network response before updating the DOM.
How CLS is calculated
CLS compares two rendered frames to calculate how much the elements of a page have moved and the fraction of the viewport that was affected by the layout shift.
There are two factors that go into CLS: impact fraction and distance fraction.
To calculate the impact fraction, you need to calculate the impact region first.
Impact region defines the area affected by the layout shift. Google compares the original frame with the frame after a layout shift and identifies all affected page elements, thus defining the impact region.
The impact region is usually a rectangle, but if you have multiple layout shifts – both horizontal and vertical – it can be a more complex shape.
Now let’s talk about the impact fraction.
To define the impact fraction, you divide the impact region by the area of the viewport (part of the page visible on the screen without scrolling down):
area of impact region / area of viewport = impact fraction
You first need to calculate the move distance.
Move distance defines the distance between a given element’s position before and after the layout shift. It pretty much answers the question: how far did the element move?
Once you’ve calculated the move distance, you can calculate the distance fraction by dividing the max move distance by viewport height:
max move distance / viewport height = distance fraction
Calculating the layout shift for a single frame
The next step is to calculate the layout shift scores. Here you multiply impact fraction by distance fraction to get the layout shift score for a single animation frame:
impact fraction x distance fraction = layout shift score for a single animation frame
Calculating Cumulative Layout Shift
Google’s researchers decided to implement a mechanism for grouping layout shifts in session windows.
Session windows are essentially time frames within the lifecycle of your page, inside of which layout shifts are summarized.
When a layout shift happens on your page, a session window is opened. It can last for a maximum of 5 seconds but will close sooner if no consecutive layout shifts occur within 1 second from the initial shift.
Layout shifts are then summarized within session windows. Your final CLS score for a given page is the score of the session window with the greatest total score – other session windows don’t influence your CLS.
To give you an example:
- Your page starts rendering.
- After 1s, a layout shift of 0.1 occurs.
- 0.5s later, another shift of 0.2 occurs.
- 2 seconds later, a shift of 0.25 occurs, and then the page is closed.
The two initial layout shifts occurred within the same session window, so we add the scores together.
The third layout shift occurred after 2 seconds, so it belongs in a separate session window. The previous session window closed one second after the second layout shift.
So in this scenario, your page’s final CLS score would be 0.1 + 0.2 = 0.3! The third layout shift doesn’t influence the final score.
Other things you should know about CLS
Intentional layout changes
CLS ignores all layout shifts that appear within half a second from any user input. It’s called the input exclusion window. This means that CLS measurement stops for 500ms after every user interaction with the site. So, if the layout change is intentional and caused by the user, it won’t affect your CLS.
Animations and layout shifts
Animations can cause layout shifts, but not all of them will count towards your CLS score. Google ignores CSS transform changes – so if your animation uses the CSS transform property, it won’t affect your CLS.
Generating layout shifts
Usually, layout shifts happen while loading the page – but they can occur later as well and will contribute to your CLS score if they happen outside of the input exclusion window.
Layout shifts and content above the fold
CLS only counts shifts visible in the viewport. If something moves below the fold and the user does not see it, such a shift won’t affect CLS in the slightest.
How to measure Cumulative Layout Shift?
Since CLS can be measured both in a lab and during real user interactions, you can and should look at both your CLS lab score and your CLS Real User Data.
CLS – Lab Data
Lab Data means using tools to simulate the user’s experience. It’s exactly like lab testing – almost real, but in a controlled environment and the results only account for a small range of possible situations.
You can access your CLS lab data via the performance tools mentioned below.
CLS – Real User Data
Real User Data is data based on real user interactions. Gathered by Google and other third parties, it allows you to see the bigger picture. You can compare Real User Data with your lab results. For Google, the main source of Real User Data is Chrome User Experience Report, also known as CrUX.
CrUX data can be accessed via:
- Google’s BigQuery,
- Google Data Studio,
- PageSpeed Insights,
- CrUX API,
- Google Search Console (Core Web Vitals report).
How to improve your Cumulative Layout Shift
Use font:display values and link rel=preload
If your site is using externally hosted fonts, they might be the main cause of FOIT (Flashes Of the Invisible Text) and FOUT (Flashes Of the Unstyled Text).
When the browser downloads the fonts from an external server, it often displays blank space until the custom font loads. After downloading and displaying the font, the layout usually moves. It’s called FOIT (Flashes Of the Invisible Text).
Another scenario occurs when the browser displays one of the system fonts until the custom one is downloaded. We call that FOUT (Flashes of The Unstyled Text). Since the system font may differ from the custom one, it may take up a different amount of space. Because of that, the layout of your site might move significantly after your custom font loads.
To avoid this, you can use font:display values such as auto, swap, block, fallback, and optional. For an even better result, you can also preload font files using <link rel=preload> for key fonts – this way they will be downloaded as a priority asset.
Including width and height elements for videos and images
In the old days of the Internet, web developers used to include width and height elements everywhere on the site. It looked like this:
<img src=”example.jpg” width=”800″ height=”300″ alt=”Example Image”>
This became less popular when responsive web design took over. Due to this new approach, developers started using CSS to resize images.
Good for them, but not so much for the users affected by CLS.
With this method, space is allocated only after the browser starts downloading the image. After all the images are displayed, the layout would move, causing unnecessary shifts.
A much better solution for resizing images is using an aspect ratio. It is the ratio of width to height (e.g., 16:9).
Using the aspect ratio allows the browser to calculate the space needed to display the image – and this way reduces the risk of layout shift.
If you’re dealing with responsive images, you can use the srcset attribute. It allows you to set up several photo sizes and the browser to display the best possible size.
Wrong implementation of dynamically injected content
Dynamically injected content should never appear above content that’s already loaded. The only exception to this rule is when the change is caused by user interaction. As I mentioned before, such content won’t affect CLS if it’s loaded within 500ms after the interaction.
If you’re looking for more resources on optimizing your CLS, Google published a very informative guide to optimizing CLS – I strongly recommend it.