Back to Performance
Performance
medium
mid

What is Cumulative Layout Shift and how do you control it?

CLS is a Core Web Vital measuring unexpected layout shifts during the page's life — content jumping as images, ads, or fonts load. Good CLS is ≤ 0.1. Control it by always reserving space: width/height (or aspect-ratio) on media, min-height for async content/ads, font-display strategy + size-adjust to limit FOUT shift, and never inserting content above existing content.

6 min read·~10 min to think through

Cumulative Layout Shift (CLS) is a Core Web Vital that measures visual stability — how much content unexpectedly jumps around as the page loads. You've felt it: you go to tap a button and an image loads above it, shoving the button down, and you tap an ad instead.

How it's scored

CLS = sum of layout shift scores for unexpected shifts, where each score = impact fraction × distance fraction. (Modern CLS uses a "session window" so a long-lived page isn't unfairly penalized.)

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

Shifts in response to user interaction (within ~500ms) are excluded — those are expected.

The main causes & fixes

1. Images/videos without dimensions

html
<!-- ❌ space isn't reserved; layout jumps when it loads -->
<img src="hero.jpg" />

<!-- ✅ reserve the box -->
<img src="hero.jpg" width="800" height="600" />

Or with CSS aspect-ratio: 16 / 9. With width/height attributes, the browser computes the aspect ratio and reserves space before the image arrives.

2. Ads, embeds, iframes — reserve a min-height box for the slot so it doesn't push content when it fills.

3. Web fonts (FOUT/FOIT) — when a custom font swaps in, text reflows if its metrics differ. Mitigate with:

  • font-display: optional or swap (deliberate choice),
  • size-adjust / ascent-override on @font-face to match fallback metrics,
  • preloading the font.

4. Dynamically injected content — banners, "you have new messages" bars inserted above existing content. Either reserve space, or insert below the fold / overlay it instead of pushing.

5. Animating layout properties — animate transform/opacity, not top/height/margin.

How to measure it

  • Lab: Lighthouse, WebPageTest, Chrome DevTools Performance panel (it flags shift regions).
  • Field (real users): the web-vitals JS library, the Layout Instability API, Chrome UX Report (CrUX) — field data is what Google ranks on.

The one rule

Always reserve space for anything that loads or appears asynchronously. Images, ads, fonts, lazy content — give it a box up front.

Senior framing

The senior answer frames CLS as "reserve space proactively" and shows breadth across all the causes — not just "set image dimensions." Knowing aspect-ratio, size-adjust for font-swap shifts, the session-window scoring change, and that field data (CrUX) is what actually affects SEO — that's the depth interviewers want.

Follow-up questions

  • How does the `aspect-ratio` property help with CLS?
  • How do web fonts cause layout shift and how do you fix it?
  • Why are user-initiated shifts excluded from CLS?
  • What's the difference between lab and field CLS data?

Common mistakes

  • Omitting width/height on images.
  • Injecting banners above existing content.
  • Ignoring font-swap reflow.
  • Optimizing only lab CLS while field CLS (CrUX) stays poor.

Edge cases

  • Lazy-loaded content below the fold still shifts if not space-reserved.
  • CLS can be near-zero in lab but bad in field due to slow networks/ads.
  • Single-page apps: route transitions can shift content unexpectedly.

Real-world examples

  • News sites with ads, image-heavy product pages, sites with custom web fonts.

Related questions