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.
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.
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:
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.
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:
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 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):
<!-- 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.
- →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.