Web Performance

What Is Cumulative Layout Shift (CLS) and How to Fix It

Cumulative Layout Shift measures visual stability: how much a page jumps while loading. What CLS is, what causes it, and how to fix every common source.

StackOptic Research Team26 Apr 20268 min read
Cumulative Layout Shift — the CLS visual-stability Core Web Vital explained

You have done it a hundred times: you go to tap a button, an image or ad loads above it, the whole page jumps, and you tap the wrong thing. That frustrating jump is exactly what Cumulative Layout Shift measures. CLS is the Core Web Vital for visual stability, and it is usually the most fixable of the three. In short: CLS is the sum of unexpected layout shifts as elements move on screen, a good score is 0.1 or less at the 75th percentile, and the fix is almost always to reserve space in advance so nothing has to jump. This guide explains what CLS is, what causes it, and how to eliminate every common source.

It is the deep-dive behind the visual-stability metric in Core Web Vitals explained.

What CLS measures

CLS quantifies how much visible content moves unexpectedly while a page is loading or being used. When an element that has already rendered shifts to a new position — because something loaded above it and pushed it down, for instance — that is a layout shift. Each shift is scored by combining two factors: the impact fraction (how much of the viewport the moving content covers) and the distance fraction (how far it moved relative to the viewport). CLS reports the largest cluster of these shifts over the page's lifetime.

The key word is unexpected. Shifts that happen within 500ms of a user interaction — like expanding an accordion you just clicked — are treated as expected and do not count. CLS is specifically about content moving when the user did not ask it to.

The thresholds

CLS is assessed at the 75th percentile of page loads, and unlike the other Core Web Vitals it is a unitless score rather than a time:

CLSRating
≤ 0.1Good
0.1 - 0.25Needs improvement
> 0.25Poor

Because it is measured at the 75th percentile, most of your real loads need to be stable. A page that is steady on a fast connection can shift badly on a slow one, where images and fonts arrive late and push content around after the user has started reading.

The top causes of CLS

Almost all layout shift comes from a short list of causes, and each has a direct remedy.

CauseWhy it shiftsFix
Images/videos without dimensionsBrowser reserves no space until the file loads, then content jumpsSet width/height or CSS aspect-ratio
Ads, embeds, iframesThey inject space after the page has renderedReserve a fixed-size slot up front
Web fonts (FOIT/FOUT)Text reflows when the custom font swaps infont-display, preload key fonts, match fallback metrics
Dynamically injected contentBanners/notices pushed in above existing content shove it downReserve space, or insert below the fold / on interaction
Late-loaded CSS or animationsNon-composited animations and late styles move layoutAnimate transform/opacity; load critical CSS early

How to fix CLS

1. Always set dimensions on media

This is the single most important fix. When an <img> or <video> has explicit width and height attributes, the browser can compute its aspect ratio and reserve exactly the right space before the file arrives — so when it loads, nothing moves. Modern browsers use the width/height attributes to do this even with responsive CSS, and you can also use the CSS aspect-ratio property. Whichever you choose, the rule is simple: every image and video should reserve its space in advance. This also overlaps with image work generally — see how to optimize images for the web.

2. Reserve space for ads, embeds and iframes

Ads are a notorious CLS source because their content arrives late and at variable sizes. Reserve a fixed-size container for each ad slot and embed (a sized placeholder), so when the content loads it fills a space that already existed rather than pushing the page around. If an ad can return different sizes, reserve the most likely or largest, and avoid placing ads inline within content the user is already reading.

3. Handle web fonts carefully

Custom fonts cause shift in two ways: FOIT (flash of invisible text), where text is hidden until the font loads, and FOUT (flash of unstyled text), where a fallback shows first and then reflows when the custom font swaps in. Reduce both by setting font-display: swap (or optional), preloading the key font files so they arrive sooner, and choosing a fallback font whose metrics are close to the custom font so the swap moves text as little as possible (the size-adjust and related descriptors help). Fonts also tie into loading speed generally, covered in how to make your website load faster.

4. Never inject content above existing content

Cookie banners, promo bars, "you have a new message" notices — anything inserted at the top of the page after it has rendered shoves everything below it down, often just as the user goes to click. Either reserve space for such elements from the start (so they fill a pre-existing slot), overlay them without affecting layout (fixed/absolute positioning), or insert them below the fold. The same applies to expanding content: trigger it on interaction, where the resulting shift is treated as expected.

5. Animate the right properties

Animations that change layout properties (like top, left, width or height) force the browser to recompute layout and can register as shifts. Animate transform and opacity instead, which the browser can composite without moving surrounding content.

How to debug CLS

CLS is unusually satisfying to debug because you can see it:

  1. Open Chrome DevTools → Rendering panel and enable Layout Shift Regions. Reload the page and watch: areas that shift flash blue, showing you exactly which elements are unstable and when.
  2. Use the Performance panel, record a load, and look at the Layout Shift entries on the timeline — each names the elements involved and its score, so you can rank the worst offenders.
  3. Run PageSpeed Insights or Lighthouse, which list "Avoid large layout shifts" with the specific elements responsible.
  4. For real-user data, the web-vitals library can attribute CLS to the elements that shift for your actual visitors — useful because the worst shifts often depend on slow connections you cannot easily reproduce.

Start with the largest shift and work down; because CLS sums a cluster, fixing the one or two biggest movers usually drops the whole score under 0.1.

Lab data vs field data for CLS

As with the other Core Web Vitals, CLS comes in two forms and they can disagree. Lab data from Lighthouse or the PageSpeed Insights lab test captures only the shifts that happen during a single, scripted page load on one device — it will not see shifts triggered by scrolling, by ads that rotate, or by content that loads only after user interaction. Field data from the Chrome UX Report reflects real visits, including all the messy real-world behaviour the lab never reproduces, and it is what Google uses for ranking. This gap is bigger for CLS than for some metrics, because so many layout shifts depend on timing and interaction that a clean lab run simply does not encounter. The practical consequence: if your lab CLS looks perfect but your field CLS does not, do not dismiss the field number — instead, use real-user attribution (the web-vitals library, or the field section of PSI) to find the shifts your scripted test is missing. Diagnose with the lab, but trust the field.

CLS in single-page apps and after navigation

Two situations deserve special attention. First, single-page apps that swap content client-side can introduce shifts long after the initial load — when a route changes and new content is injected, or when data arrives and rearranges the view. CLS keeps accumulating across the life of the page, so these later shifts count; reserve space for content that will load asynchronously, and render skeletons or placeholders at the final dimensions rather than letting content pop in and reflow. Second, back/forward navigation: browsers increasingly restore pages from the back/forward cache (bfcache) instantly, which avoids re-running the layout shifts of a fresh load — but only if your page is eligible. Avoiding patterns that disqualify a page from bfcache (such as certain unload handlers) is therefore a quiet CLS win, because a restored page does not reshuffle the way a reloaded one does.

A worked example

Imagine a blog page reporting a field CLS of 0.28 — "poor". You enable Layout Shift Regions and reload: the hero image area flashes (it has no dimensions), and a moment later the whole article jumps when a custom font swaps in. Two fixes follow directly. First, add width and height to the hero image so the browser reserves its space — the first shift disappears. Second, preload the body font and set font-display: swap with a metrically-similar fallback, so the text barely moves when the font arrives — the second shift shrinks to negligible. Re-measured in the field, CLS drops to 0.04, comfortably "good". This is typical: a small number of unstable elements account for nearly all the score, so a couple of targeted fixes resolve it.

Why CLS matters

A jumpy page is more than an annoyance. It causes mis-clicks — users tap the wrong link, the wrong button, the wrong ad — which is frustrating and, on commerce sites, costly. It makes content hard to read, because the text keeps moving as you try to follow it. And it signals a lack of polish that quietly erodes trust. Because CLS is part of Google's page-experience signals, instability can also cost you a little in rankings. The happy news is that, of all the Core Web Vitals, CLS is usually the cheapest to fix: a disciplined habit of always reserving space for media, ads, fonts and injected content keeps most sites well under the threshold without any deep engineering.

Common mistakes

  • Omitting width and height on images, the most common cause of all.
  • Inserting cookie banners or promos above the fold after render.
  • Ignoring fonts, which reflow text on slow connections you do not test.
  • Animating layout properties instead of transform/opacity.
  • Testing only on fast connections, where late-loading content hides the shift.

Go deeper

Want your CLS measured alongside the rest of your Core Web Vitals, SEO and security? Analyse any URL with StackOptic — free, no sign-up.

Frequently asked questions

What is Cumulative Layout Shift (CLS)?

CLS is a Core Web Vital that measures visual stability — how much the content of a page moves around unexpectedly while it loads or while a user interacts with it. Each unexpected shift gets a score based on how much of the viewport moved and how far; CLS sums the worst cluster of these shifts over the page's life. A low CLS means content stays put, so users do not lose their place or mis-click.

What is a good CLS score?

At the 75th percentile of page loads, a good CLS is 0.1 or less. Between 0.1 and 0.25 is 'needs improvement', and above 0.25 is 'poor'. Unlike LCP and INP, CLS is a unitless score rather than a time. Because it is measured at the 75th percentile, most of your real visitors should experience a visually stable page, not just your fastest or luckiest loads.

What causes layout shift?

The most common causes are images and videos loaded without width and height attributes (so the browser reserves no space until they arrive), ads, embeds and iframes that inject space after the page has rendered, web fonts that cause text to reflow when they swap in, and content dynamically inserted above content the user is already looking at. In each case the browser did not know how much room something would need.

How do I fix Cumulative Layout Shift?

Reserve space in advance. Always set width and height (or use CSS aspect-ratio) on images and videos so the browser holds their space before they load. Reserve fixed slots for ads, embeds and iframes. Manage fonts with font-display and preloading to limit reflow. And never inject banners, notices or content above existing content once the page has rendered. These steps usually bring CLS comfortably under 0.1.

How do I debug CLS in Chrome DevTools?

Open Chrome DevTools, go to the Rendering panel, and enable 'Layout Shift Regions' — areas that shift will flash blue as they move, showing you exactly which elements are unstable. The Performance panel also records layout shifts on its timeline with the elements involved, and PageSpeed Insights and Lighthouse list the largest shifts in their diagnostics so you can target the worst offenders first.

Analyse any website with StackOptic

Get the full technology stack, performance, security and SEO report in seconds — free.

Analyse a website

Related articles