Eliminating Cumulative Layout Shift (CLS) — getting visual stability under control
Cumulative Layout Shift is the metric that measures how often the ground gets pulled out from under your fingers. You’re about to tap a button, a banner loads in at that exact moment, everything slides down — and your finger lands in the wrong spot. Those unwanted jumps are exactly what CLS counts. Unlike loading-time metrics, it isn’t about when something appears, but about whether it stays put. CLS is part of the Core Web Vitals and therefore a direct ranking input — but above all, a high value is a reliable symptom of a sloppily built layout.
What CLS actually measures
CLS quantifies unexpected layout shifts across a page’s entire lifecycle. A layout shift happens when a visible element changes its position from one rendered frame to the next — without the user triggering it. Important: inserting new DOM elements or resizing an element is not by itself a shift. It only counts when it pushes other, already-visible elements out of place.
The score for each shift comes from two factors:
- Impact fraction — how much of the visible viewport is affected by the unstable elements between two frames.
- Distance fraction — the greatest distance any unstable element travels horizontally or vertically, divided by the larger viewport dimension.
Multiply the two and you get the layout-shift score of a single jump. A small element drifting a little is harmless. A large block leaping far down the page is expensive.
Session windows instead of a blunt sum
The metric used to be literally “cumulative” — every shift was summed up until the page ended. That unfairly punished long pages and single-page apps. Today the session window approach applies: shifts that follow each other with less than 1 second in between form a window (5 seconds maximum length). Only the largest of these bursts is scored, not the total sum. In practice that means a single bad jump during load wrecks your value — scattered small movements over minutes hurt less.
The thresholds: under 0.1 is the target
Google rates CLS in three tiers, measured at the 75th percentile of page loads, segmented by mobile and desktop:
| Rating | CLS value | |---|---| | Good | ≤ 0.1 | | Needs improvement | > 0.1 to ≤ 0.25 | | Poor | > 0.25 |
The 75th percentile is the point many people miss: it isn’t enough that the page loads stably for you. Three out of four real users must experience a value of 0.1 or better — including those on slow connections, where ads and fonts load late and tear the layout apart exactly then.
The main causes — and where they come from
Almost every real-world CLS value above 0.1 traces back to a small handful of patterns.
Images, iframes and embeds without reserved dimensions
The classic. An <img> without width/height takes up zero space in the layout until the file loads — then it pops open and shoves everything below it away. The same applies to iframes (YouTube embeds), map widgets and social-media cards. The higher up the element sits, the more it shifts.
Late-loading web fonts (FOUT/FOIT)
A web font almost never renders pixel-identical to the system fallback. When the browser shows the fallback font first (FOUT, flash of unstyled text) and then swaps to the web font, line height and text width change — the text reflows and everything below it slides. With FOIT (flash of invisible text) the text stays invisible first and then jumps in. Both produce shifts, often late and therefore especially annoying.
Dynamically injected content above existing content
Cookie banners, newsletter bars, “you have 3 items in your cart” notices, A/B test variants: anything inserted via JavaScript above already-visible content pushes that content down. Particularly insidious because it often happens after the first render — that is, right when the user is already reading.
Ads and third-party widgets that re-size themselves
Ad slots often only know their final height once the ad has loaded. If you haven’t reserved space, the slot expands and shoves the content. Third-party widgets (chat bubbles, review badges) have the same problem.
The levers: how to remove layout jumps
Explicit dimensions or aspect-ratio on all media
Set the width and height attributes on every <img> and <video>. Modern browsers compute the aspect-ratio from them automatically and reserve the space before the file loads — the slot is correctly sized from the start. For responsive images scaled via CSS, still provide the attributes and let CSS (width: 100%; height: auto;) handle display. For iframes and embeds, reserve the space with CSS aspect-ratio or a fixed-dimension container.
font-display and size-adjust against font jumps
Control font behaviour via font-display. font-display: optional is the safest for CLS — the browser only uses the web font if it’s available immediately, otherwise it stays on the fallback with no later swap. If you want the web font guaranteed, combine font-display: swap with the @font-face descriptors size-adjust, ascent-override and descent-override: this tunes the fallback font metrically so it occupies the same space as the web font — the swap then happens without a reflow.
Reserve space for ads, embeds and lazy-loaded content
Give every ad slot a fixed minimum height in CSS matching the most common ad size. A briefly visible empty placeholder beats a jump. Cookie banners and notification bars belong as an overlay (position: fixed) above the content or at the bottom edge — not in the normal document flow above the content, where they shove everything away.
Never insert content above already-visible content
If you must inject something dynamically, do it below the viewport content or reserve the space in advance. Exception: shifts within 500 milliseconds of a genuine user interaction (click, tap) count as expected and don’t enter the CLS score. That’s why expanding accordions and “load more” buttons aren’t a CLS problem — the user triggered them.
CSS transform instead of position changes for animations
When you animate elements, use the CSS transform property instead of top, left or margin. Transform animations run on their own compositing layer and trigger no layout reflow — so they don’t count toward the CLS score. Position-based animations, by contrast, move real layout and produce shifts.
Distinguishing it from LCP and INP
CLS is one of three Core Web Vitals and measures something fundamentally different from its two siblings:
- LCP (Largest Contentful Paint) measures loading speed — when the largest visible element finishes rendering. It’s about when something is there.
- INP (Interaction to Next Paint) measures responsiveness — how fast the page reacts to input. It’s about how briskly it answers.
- CLS measures visual stability — whether what’s already there stays in place.
A page can load lightning-fast (good LCP) and still have catastrophic CLS because fonts and ads slide in late. The three metrics don’t overlap — you have to watch all three individually. CLS is usually the easiest to fix, because the causes are so clearly nameable.
FAQ
FAQ
- A CLS of 0.1 or less counts as good, above 0.25 as poor — measured at the 75th percentile of real user visits, segmented by mobile and desktop. So it is not enough that it loads stably for you; three out of four real users must hit the value.
- Lab tools (Lighthouse) measure a single, often fast run. Field data (CrUX, Search Console) captures real users on slow connections, with cleared caches and late-loading ads or fonts — which is exactly where the jumps happen. For CLS, always trust the field data.
- That fixes the most common cause, but rarely all of them. Also check web fonts (font-display, size-adjust), reserved heights for ad slots and embeds, and dynamically injected content like cookie banners. CLS is usually a sum of several small sources.
- No, provided the shift happens within 500 milliseconds of the user interaction. Expanding accordions, "load more" buttons or opened menus count as expected and do not enter the CLS score.
- CLS is part of the Core Web Vitals and therefore a ranking signal — though a comparatively weak one next to relevance and content quality. The bigger lever is user experience: jumping layouts increase misclicks and bounces, and that has an indirect effect.
At what CLS value is a page "good"?
Why is my CLS good in the lab but bad in field data?
Is setting width and height on images enough?
Do layout jumps after a click count against me?
How does CLS relate to ranking?
Conclusion
CLS is the most approachable of the three Core Web Vitals, because the causes are so concrete: media without dimensions, fonts sliding in, dynamically injected content, expanding ads. Set width/height on every image, tame fonts with font-display and size-adjust, and reserve space upfront for ads and banners, and you push your value below the 0.1 threshold in almost every case. Always measure at the 75th percentile of field data, not the pretty lab run — because that’s where, for slow real users, the jumps that count are born.
If you want the full picture of technical crawlability and performance, you’ll find it in the sister article on technical SEO.
Entdecke mehr
Brotli / Gzip Compression
Server-side compression methods that shrink text resources like HTML, CSS and JavaScript before transmission — Brotli usually delivers better ratios than Gzip today.
LexikonTechnical SEO — what Google actually has to crawl, render and index
How crawl budget, robots, sitemap, JS rendering, indexing, canonical and Core Web Vitals fit together — the full arc for production sites.
NewsGoogle Search Central Live Toronto 2026 — what Google officially said about the future of search
Information Gain as the new guideline, Google-Extended clarified, AI Mode with 93% zero-click. The key statements from Toronto.