Cumulative layout shift: how to find it and stop it

Cumulative layout shift is the Core Web Vital for visual stability, and the target is 0.1 or less at the 75th percentile. This chapter is a four-step way to find the element that moves, name it in the audit, and reserve its space — including the command we ran on BBC News.

Implementation6 min read2539 views
Cumulative layout shift: how to find it and stop it

Cumulative layout shift is the score for how much a page's content jumps around while it is still loading. It is the third Core Web Vital, and the target is 0.1 or less at the 75th percentile of page loads; 0.25 and above is poor. This chapter is a four-step way to find the shift, name the element that caused it, and reserve the space so it stops moving — plus a one-line command that reads the number for any URL.

Read this first

You need one page you can edit and a browser. There is no build step and nothing to install beyond the command below. The other two Core Web Vitals are covered in their own chapters: largest contentful paint is the loading metric, and interaction to next paint is the responsiveness one. This chapter is about the third: visual stability. If you want the load-side picture across a panel of real sites, the total blocking time survey is the measured companion.

What cumulative layout shift actually measures

A layout shift happens when a visible element changes its starting position from one frame to the next. Cumulative layout shift is "a measure of the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifecycle of a page" (web.dev, read 2026-10-01). The word to hold onto is unexpected. A carousel that advances on its own shifts the layout; the same carousel responding to a tap does not count, because the browser sets aside any shift within 500 milliseconds of a real input.

A single layout shift score is the product of two fractions. The impact fraction is how much of the viewport the unstable elements covered before and after the move, as a share of the whole viewport. The distance fraction is how far the furthest of them travelled, as a share of the viewport's larger dimension. Multiply the two and you have that shift's score: a banner that fills half the viewport and drops by a quarter of its height scores 0.75 × 0.25 = 0.1875.

Layout shift is not a page that moves. It is a page that moves while you are not asking it to.

CLS is not the sum of every shift on the page. It is the largest session window: shifts that happen within one second of each other, grouped together, with the window itself capped at five seconds. One bad burst early in the load can set your score even when the rest of the page is calm. That is why a single fixable element usually moves the number more than a hundred small ones.

Do it in this order

Four steps. Each one has a completion mark you can check before moving on.

  1. Get the number first. Run the command below against the live URL. Done when you have a value and the band it lands in: 0.1 or less, between 0.1 and 0.25, or over 0.25.
  2. Find the element, not the section. Read the layout-shifts audit. Done when you can name the node — an <img>, an <iframe>, a font swap — and not just "the top of the page".
  3. Reserve the space before you tune anything. Give that element a width and height, or a CSS aspect-ratio. Done when it occupies the same box before and after it loads.
  4. Re-run and compare. The same command, the same page. Done when the score drops and the element is gone from the shift list.

Step three is where a fix stops being a guess. Reserving space removes the shift; shrinking the file only shortens the wait.

The deliverable: a cause table and a one-line audit

Almost every shift you will meet comes from one of four causes. The table maps each cause to how it shows up in the audit and to the fix that actually addresses it.

CauseIn the auditThe fix
An image, video or iframe with no declared size"Media element lacking an explicit size"width and height attributes, or aspect-ratio in CSS
A web font that swaps in at a different size"Web font loaded"font-display: swap or optional, plus a preload and size-adjust
An ad, embed or widget that brings its own boxan unsized element appears mid-pagereserve a fixed min-height for the slot
Content added after a request returnstext or cards move once the fetch resolvesrender a placeholder of the same size first

The audit is one line, and it reads the same JSON that Lighthouse prints in the browser.

npx lighthouse https://example.com/ \
  --only-audits=cumulative-layout-shift,layout-shifts \
  --output=json --output-path=cls.json --quiet

Run against BBC News on 1 October 2026, the command returns a cumulative layout shift of 0.764 and lists four shifts. Three of them, worth 0.710, 0.054 and 0.038, are labelled "Media element lacking an explicit size". The fourth, worth 0.003, is a web font swap.

Shift scoreCause
0.710Media element lacking an explicit size
0.054Media element lacking an explicit size
0.038Media element lacking an explicit size
0.003Web font loaded

Read that as one page, fetched once, and not as a verdict on the site. It is a demonstration of the command, and it happens to show the two causes that dominate the web. Two causes cover the whole score.

What goes wrong

Three failures show up more than any others. All three look fixed in a browser on a fast connection.

  1. Fixing the image instead of the box. Compressing the file or moving it behind a CDN shortens the load but does not stop the shift. If the browser does not know the size in advance, the layout still moves when the image lands. Give the element its dimensions.
  2. Tuning the font instead of the fallback. font-display: swap removes the invisible-text delay, but a fallback font with different metrics still reflows the line. Pair it with size-adjust, or preload the web font so it arrives with the stylesheet.
  3. Trusting the lab number. Lab tools load the page in a synthetic environment and only see shifts that happen during load. Field CLS from real users can be higher, because it also counts what happens after they scroll and interact.

Common questions

What is a good cumulative layout shift score?

0.1 or less at the 75th percentile of page loads, measured separately for mobile and desktop. Above 0.25 is poor. The 0.1 is a target, not a per-view pass mark — at the 75th percentile, a quarter of your loads can still be worse.

How do I find what is causing cumulative layout shift?

Run the layout-shifts audit, which lists each shift with the node that moved and, in most cases, the reason for it. The reasons are coarse: "Media element lacking an explicit size" points at a class of problem, not at one image. You then find the element by its size and position, not by its content.

Does cumulative layout shift affect SEO?

It is a Core Web Vital, and Core Web Vitals are part of Google's page experience signals. What it changes for a real visitor is whether they can tap the thing they aimed at, so treat a bad score as a user problem that happens to be ranked, not as a ranking lever you can pull alone.

Can cumulative layout shift be negative, or reset to zero?

No, the score is a sum of positive values and never falls below zero. It does reset when a page is restored from the back/forward cache, because the browser treats that as a fresh visit. We have not seen a tool report a negative value, and there is no documented case of one.

The boundary worth saying plainly: this measures load-time shifts in a lab, and it cannot see the shift an ad causes thirty seconds after a reader scrolls. That does not make the number useless — it makes it a floor. Reserve the space, drive the load-time score to zero, then watch the field number for what happens afterwards. Keeping that number in view across the pages people actually land on is part of what QueryWin works on.

Part of the QueryWin handbook · Level 2

Cumulative layout shift: how to find it and stop it