Frontend Performance/Core Web Vitals
Lesson 5 of 20 · Episode 5

Cumulative Layout Shift (CLS)

Why the page jumps under your finger, how the score is computed, and how to pin layout so it never moves.

CLSLayout shiftReserved space
Watch on YouTube ↗

You go to tap “Cancel,” an image loads above it, the whole page lurches down, and your finger lands on “Place order.” That lurch is a layout shift, and Cumulative Layout Shift (CLS) is the metric that scores how much your page jumps around. Good is ≤ 0.1.

See it for yourself

Feel the jank, then pin it

Below is a checkout card. Load it with Reserve space off and watch the product image shove the buttons down right as you'd reach for them. Flip the toggle on and load again — the space is held, nothing moves, and CLS drops to zero:

InteractiveA mis-tap waiting to happen
Checkout
CancelPlace order
CLS score
0.31
Poor

The image pops in and shoves the buttons down — a tap meant for “Cancel” lands on “Place order.”

With no reserved dimensions the image pops in at full height and pushes everything below it. Reserving space fixes it completely.
Definition

What actually counts as a shift

A layout shift happens when a visible element changes its start position between two frames. The key word is visible: a brand-new element appearing doesn't hurt your score by itself — it only counts when it pushes something the user could already see. And shifts the user caused (within 500 ms of a tap or keypress) are excused.

Key idea
CLS measures unexpected movement. Content that moves because the user clicked “Load more” is expected and doesn't count. Content that moves because an ad finally loaded is exactly what it punishes.
The math

How the score is computed

Each shift scores impact fraction × distance fraction. Impact is how much of the viewport the moving content touched (its area before and after, unioned). Distance is how far it moved, relative to the viewport. Drag the slider:

Interactiveimpact × distance
shifted
Impact fraction0.65· area touched by the shift
Distance fraction0.25· how far it moved
Layout-shift score =0.163
impact × distance = 0.65 × 0.25. Good ≤ 0.1 · Poor > 0.25.
A big element that moves a long way scores worst. The dashed box is the union of the before and after positions — that's the impact fraction.

Those per-shift scores are summed within session windows — a burst of shifts less than 1 s apart, capped at 5 s — and your CLS is the worst window. Thresholds: ≤ 0.1 good, 0.1–0.25 needs work, > 0.25 poor.

The usual suspects

The three big causes — and their fixes

1. Images & videos with no dimensions

Without width/height, the browser reserves zero space until the file loads, then snaps to full size. Always set dimensions (or an aspect-ratio for responsive images):

reserve the space up front
<!-- The browser reserves the right box before the file arrives -->
<img src="/hero.webp" width="1200" height="630" alt="…" />

/* Or, for fluid images, lock the ratio in CSS */
img { aspect-ratio: 16 / 9; width: 100; height: auto; }

2. Ads, embeds & injected content

Third-party content loads late and unpredictably. Reserve a min-height placeholder so the ad fills empty space instead of shoving content. For things like cookie banners, use an overlay that sits on top of the page rather than pushing it. And if a shift truly must happen, make it user-triggered so it's expected.

3. Web fonts (FOUT)

When your custom font swaps in for the fallback, differing metrics reflow the text. Preload critical fonts and pick a fallback with similar sizing (via size-adjust / font-display) so the swap barely moves anything.

Q1Sort each scenario
Does each scenario count against CLS?
An ad loads and pushes the article down
Content appears below after you click “Load more”
Text reflows when the web font swaps in
An element far below the fold shifts (never seen)
Q2Multiple choice
What's the single most effective fix for image-caused layout shift?
Q3Multiple choice
A single layout shift's score is calculated as…
Q4Multiple choice
Which CLS value is in the “good” range?
Key takeaways
  • CLS scores unexpected movement of visible content. Good ≤ 0.1.
  • Each shift = impact fraction × distance fraction; your score is the worst session window.
  • Top cause: images/videos/ads with no reserved dimensions — set width/height or aspect-ratio.
  • Reserve space for ads (min-height), overlay cookie banners, and preload fonts.
  • User-triggered shifts (within 500 ms of an interaction) are excused.
← Previous
4. Largest Contentful Paint (LCP)
Next →
6. Interaction to Next Paint (INP)