Optimize Cumulative Layout Shift

Learn how to avoid sudden layout shifts to improve user-experience

Published: May 5, 2020, Last updated: Feb 7, 2025

Cumulative Layout Shift (CLS) is one of the three Core Web Vitals metrics. It measures the instability of content by combining how much visible content has shifted in the viewport with the distance the affected elements moved.

Layout shifts can be distracting to users. Imagine you've started reading an article when all of a sudden elements shift around the page, throwing you off and requiring you to find your place again. This is very common on the web, including when reading the news, or trying to click those 'Search' or 'Add to Cart' buttons. Such experiences are visually jarring and frustrating. They're often caused when visible elements are forced to move because another element was suddenly added to the page or resized.

To provide a good user experience, sites should strive to have a CLS of 0.1 or less for at least 75% of page visits.

Good CLS values are under 0.1, poor values are greater than 0.25 and anything in between needs improvement
Good CLS values are 0.1 or less. Poor values are greater than 0.25.

Unlike the other Core Web Vitals, which are time-based values measured in seconds or milliseconds, the CLS score is a unitless value based on a calculation of how much content is shifting and by how far.

In this guide, we'll cover optimizing common causes of layout shifts.

The most common causes of a poor CLS are:

  • Images without dimensions.
  • Ads, embeds, and iframes without dimensions.
  • Dynamically injected content such as ads, embeds, and iframes without dimensions.
  • Web fonts.

Understand the causes of layout shifts

Before you start looking at solutions to common CLS issues, it's important to understand your CLS score and where the shifts are coming from.

CLS in lab tools versus field

It is common to hear developers think the CLS measured by the Chrome UX Report (CrUX) is incorrect as it does not match the CLS they measure using Chrome DevTools or other lab tools. Web performance lab tools like Lighthouse may not show the full CLS of a page as they typically do a basic load of the page to measure some web performance metrics and provide some guidance (though Lighthouse user flows do allow you measure beyond the default page load audit).

CrUX is the Google dataset of the Web Vitals program, and for that, CLS is measured throughout the full life of the page and not just during the initial page load that lab tools typically measure.

Layout shifts are very common during page load, as all the necessary resources are fetched to initially render the page, but layout shifts can also happen after the initial load. Many post-load shifts may occur as the result of a user interaction and therefore will be excluded from the CLS score as they are expected shifts—as long as they occur within 500 milliseconds of that interaction.

However, other post-load shifts that are unexpected by the user may be included where there was no qualifying interaction—for example, if you scroll further along the page and lazy-loaded content is loaded and that causes shifts. Other common causes of post-load CLS are on interactions of transitions, for example on Single Page Apps, which take longer than the 500 millisecond grace period.

PageSpeed Insights shows both the user-perceived CLS from a URL in its "Discover what your real users are experiencing" section, and the lab-based load CLS in its "Diagnose performance issues" section. Differences between these values are likely the result of post-load CLS.

PageSpeed Insights showing URL-level data highlighting the real user CLS which is considerably larger than the Lighthouse CLS
In this example, CrUX measures a much larger CLS than Lighthouse.

Identify load CLS issues

When the CrUX and Lighthouse CLS scores of PageSpeed Insights are broadly aligned, this usually indicates there is a load CLS issue that was detected by Lighthouse. In this case Lighthouse will help with two audits to provide more information on images causing CLS due to missing width and height, and also list all the elements that shifted for the page load along with their CLS contribution. You can see these audits by filtering on the CLS audits:

Lighthouse Screenshot showing the CLS audits providing more information to help you identify and address CLS issues
Lighthouse's detailed CLS diagnostics.

The Performance panel in DevTools provides a wealth of information on layout shifts:

Layout Shift records being displayed in the Chrome DevTools performance panel.
After recording a new trace in the Performance panel, the Layout Shifts track of the results is populated with purple bars displaying a Layout Shift clusters. Clicking the diamonds shows an animation of the shift and details in the Summary panel.

Layout shifts are highlighted in the Layout shifts track. The purple line groups shifts into shift clusters with the diamonds showing individual shifts in that cluster. The size of the diamond is proportional to the size of the shift allowing you to hone in on the largest shifts.

Clicking on a shift shows a pop up with an animation of the shift and highlights the elements shift in purple.

Additionally, the Summary view for a Layout Shift record includes the start time, the shift score as well as the elements shifted. This is particularly helpful to get more detail on load CLS issues since this is easily replicated with a reload performance profile.

This also links to the Layout shift culprits insight displayed in the Insights panel on the left, which shows the total CLS at the top, as well as possible reasons for layout shifts.

Identify post-load CLS issues

Disagreement between the CrUX and Lighthouse CLS scores often indicates post-load CLS. These shifts can be tricky to track down without field data. For information on collecting field data, see Measure CLS elements in the field.

The live metrics view of the Performance Panel lets you interact with the page and monitor the CLS score to identify interactions causing large layout shfts.

Layout Shift records being displayed in the live metrics screen of Chrome DevTools performance panel.
The live metrics view of the Performance Panel allows monitoring of a web page's CLS score while interacting with the page.

As an alternative to using the DevTools, you can browse your web page while recording layout shifts using a Performance Observer pasted into the console.

After you set up shift monitoring, you can try to replicate any post-load CLS issues. CLS often happens while the user scrolls through a page, when lazy-loaded content loads fully without space reserved for it. Content shifting when the user holds the pointer over it is another common post-load CLS cause. Any content shift during either of these interactions counts as unexpected, even if it happens within 500 milliseconds.

For more information, see Debug layout shifts.

After you've identified any common causes of CLS, the timespans user flow mode of Lighthouse can also be used to ensure typical user flows don't regress by introducing layout shifts.

Measure CLS elements in the field

Monitoring CLS in the field can be invaluable in determining what circumstances CLS happens in and narrowing down the possible causes. Like most lab tools, field tools measure only the elements that shifted, but that usually provides enough information to identify the cause. You can also use CLS field measurements to determine which issues are the highest priority to fix.

The web-vitals library has attribution functions that let you collect this additional information. For more information, see Debug performance in the field. Other RUM providers have also started collecting and presenting this data similarly.

Common causes of CLS

Once you have identified the causes of CLS, you can start working on fixing the issues. In this section we will show some of the more common reasons for CLS, and what you can do to avoid them.

Images without dimensions

Always include width and height size attributes on your images and video elements. Alternatively, reserve the required space with CSS aspect-ratio or similar. This approach ensures that the browser can allocate the correct amount of space in the document while the image is loading.

Images without width and height specified.
Images with width and height specified.
Lighthouse report showing the before/after impact to Cumulative Layout Shift after setting dimensions on images
Lighthouse 6.0 impact of setting image dimensions on CLS.

History of width and height attributes on images

In the early days of the web, developers would add width and height attributes to their <img> tags to ensure sufficient space was allocated on the page before the browser started fetching images. This would minimize reflow and re-layout.

<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

width and height in this example don't include units. These "pixel" dimensions would ensure that the browser reserved a 640x360 area in the page's layout. The image would stretch to fit this space, regardless of whether the true dimensions matched it.

When Responsive Web Design was introduced, developers began to omit width and height and started using CSS to resize images instead:

img {
  width: 100%; /* or max-width: 100%; */
  height: auto;
}

However, because the image size isn't specified, space can't be allocated for it until the browser starts to download it and can determine its dimensions. As images load, text shifts down the page to make room for them, creating a confusing and frustrating user experience.

This is where aspect ratio comes in. The aspect ratio of an image is the ratio of its width to its height. It's common to see this expressed as two numbers separated by a colon (for example, 16:9 or 4:3). For an x:y aspect ratio, the image is x units wide and y units high.

This means if we know one of the dimensions, the other can be determined. For a 16:9 aspect ratio:

  • If puppy.jpg has a 360px height, width is 360 x (16 / 9) = 640px
  • If puppy.jpg has a 640px width, height is 640 x (9 / 16) = 360px

Knowing the aspect ratio for an image allows the browser to calculate and reserve sufficient space for the height and associated area.

Modern best practice for setting image dimensions

Because modern browsers set the default aspect ratio of images based on an image's width and height attributes, you can prevent layout shifts by setting those attributes on the image and including the preceding CSS in your style sheet.

<!-- set a 640:360 i.e a 16:9 aspect ratio -->
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

All browsers will then add a default aspect ratio based on the element's existing width and height attributes.

This calculates an aspect ratio based on the width and height attributes before the image has loaded. It provides this information at the very start of layout calculation. As soon as an image is told to be a certain width (for example width: 100%), the aspect ratio is used to calculate the height.

This aspect-ratio value is calculated by major browsers as the HTML is processed, rather than with a default User Agent style sheet (see this post for a deep dive into why), so the value is displayed a little differently. For example, Chrome displays it like this in the Styles section of the Element panel:

img[Attributes Style] {
  aspect-ratio: auto