Cumulative Layout Shift: how to find and fix what moves

Short answer

CLS measures how much visible content jumps around unexpectedly. Aim for 0.1 or less. The element that moved usually isn't the cause: something above it loaded late and pushed it. Reserve space for images, ads and late content before they arrive.

What CLS measures

Cumulative Layout Shift is the Core Web Vital for visual stability. It's what makes you tap the wrong button because the page moved at the last moment.

GoodNeeds improvementPoor
0.1 or lessOver 0.1, up to 0.25Over 0.25
  • It's a score, not a time. Each shift is scored on how much of the viewport moved and how far.
  • It takes the worst burst. Shifts less than a second apart are grouped, up to 5 seconds, and CLS is the highest group's total.
  • It covers the whole visit. Shifts can happen long after load, so a test that stops at load can miss them.
  • Expected shifts don't count. A shift within 500 ms of a click, tap or key press is left out. Scrolling doesn't count as that kind of input.

The score Google uses comes from real Chrome visitors at the 75th percentile, which you can see in Search Console's Core Web Vitals report or PageSpeed Insights.

How to find the shift

1Run the snippet 2 minutes

Load the page, open DevTools (F12), go to the Console and paste this, then scroll down the page:

// Logs each unexpected layout shift and what moved
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.hadRecentInput) continue;
    console.log(entry.value.toFixed(4), Math.round(entry.startTime) + ' ms', entry.sources.map((s) => s.node));
  }
}).observe({ type: 'layout-shift', buffered: true });

Each line shows the shift's score, when it happened and the elements that moved. These are single shifts, so they won't add up to the page's CLS.

2Use the Performance panel 3 minutes

Record a page load in the Performance tab. It marks layout shifts on the timeline, so you can see what loaded just before each one.

Test as a first-time visitor on a phone-sized screen. Cached images and fonts can hide shifts, and cookie banners only appear on a first visit.

The usual causes

CauseWhat you'll see
Images with no sizeText jumps down when the image arrives
Ads and embedsA slot grows or collapses after load
Content added lateA banner or block appears above what you're reading
Web fontsText reflows when the font swaps in
Layout animationsAnimating top, left or margin moves other elements

How to fix them

  • Images and video: set width and height, or use CSS aspect-ratio.
  • Ads and embeds: give the slot a min-height based on its smallest likely size, and keep the space if nothing fills it.
  • Late content: use a placeholder, put it lower on the page, or load it when someone asks with a button.
  • Web fonts: preload key fonts, pick a close fallback and consider font-display: optional.
  • Animations: use transform, which doesn't move other elements.
  • Back and forward navigation: keep pages eligible for the back/forward cache, so they're restored without shifting.
<img src="/photo.webp" width="800" height="600" alt="...">

<style>
  .ad-slot { min-height: 250px; }
  .video { aspect-ratio: 16 / 9; }
</style>

How crawlers report this

These labels come from PageSpeed data, so they can change between versions.

Screaming FrogSitebulbWhat it means
PageSpeed: Layout Shift CulpritsNo direct matchSomething on the page is likely causing shifts.
Images: Missing Size AttributesAdd dimensions to imagesImages have no set size, so the browser can't reserve space.
PageSpeed: Font DisplayEnsure text remains visible during webfont loadFonts may change how text appears as they load.

Hard to explain to a developer?

See what moved and why

SEOSnip's Speed tab records the layout shifts your browser saw as you used the page. It's not field data, so use it to find the cause. You get:

  • Each shift with its score and time, worst first
  • The elements that moved, how far, and a highlight on the page
  • A diagram of the move, with the likely cause where one can be found
  • A ticket for one shift or the whole page, with that evidence attached