Cumulative Layout Shift (CLS)
What Cumulative Layout Shift measures, how the score is calculated (impact × distance), session windows, thresholds, the common causes, and how to fix and debug them.
Cumulative Layout Shift (CLS) is the Core Web Vital for visual stability — how much visible content unexpectedly moves while a page is in use. It's a unitless score (impact fraction × distance fraction per shift), and since June 2021 it's the largest session window of shifts, not the lifetime sum. Good is ≤ 0.1 at the 75th percentile of field data; 0.1–0.25 needs improvement; > 0.25 is poor. The usual culprits are unsized images/ads/iframes/embeds, web fonts, and content injected above the fold — fix them by reserving space (width/height or aspect-ratio), tuning font-display, and animating with transform. Lighthouse often reads near-0 because it doesn't interact with the page or run the full page lifecycle — field data (CrUX) is what Google actually ranks on.
TL;DR — Cumulative Layout Shift (CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.) measures how much stuff on a page moves around on its own while you’re trying to read or tap it — the image that loads late and shoves the text down, the button that jumps right as you go to click it. It’s scored from 0 up, and 0.1 or less is good. Most of it comes from elements that didn’t reserve their space before they loaded.
What CLS is
You’ve felt this even if you’ve never heard the term. You’re reading an article, an ad or image finishes loading above where you’re looking, and suddenly the whole page jumps down. Or you go to tap “Cancel” and a banner pops in, so your tap lands on “Confirm” instead. That unexpected movement is a layout shift, and Cumulative Layout Shift is Google’s way of putting a number on how bad it is.
It’s one of the three Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. — the trio of page-experience metrics Google tracks, alongside Largest Contentful PaintLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. (how fast the main content loads) and Interaction to Next PaintInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. (how quickly the page responds when you tap). CLS is the one about visual stability: does the page hold still?
How the score works (roughly)
CLS is a score, not a time. A CLS of 0.05 doesn’t mean 50 milliseconds of anything — it’s a unitless number. The bigger the chunk of the screen that moves, and the farther it moves, the higher (worse) the score.
The targets are simple:
- 0.1 or less — good.
- 0.1 to 0.25 — needs improvement.
- Over 0.25 — poor.
One nice detail: shifts that happen right after you do something — tap a button, open a menu — don’t count against the page, because you caused them and you expect them. Only the unexpected movement counts.
Evidence for this claim CLS uses the largest session window of unexpected layout shifts, with gaps under one second and a maximum five-second window; recent discrete input can exclude a shift. Scope: Current CLS session-window and recent-input rules. Confidence: high · Verified: web.dev: Cumulative Layout ShiftWhy it happens (and the fix)
Almost every layout shift comes down to the same thing: something loaded and took up space the page hadn’t reserved for it. The big ones:
- Images and videos without sizes. The browser doesn’t know how tall the image
is until it arrives, so the text below it gets pushed down when it does. The fix:
always give images a
widthandheight(or a CSSaspect-ratio) so the browser holds the spot. - Ads, embeds, and iframesHTML element that displays one webpage inside another — how embeds work.. Same problem — reserve space for them.
- Web fonts. When a custom font swaps in for the fallback, text can reflow.
- Pop-ins. Cookie banners, “you might also like” boxes, anything injected above content you’re already looking at.
The mental rule: if something is going to appear later, leave a hole the right size for it so nothing else has to move when it shows up.
Want the actual formula, the “session window” rule, why lab and field CLS numbers disagree, and the full causes-and-fixes list? Switch to the Advanced tab.
TL;DR — CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. is the Core Web Vital for visual stability. Each shift scores as
impact fraction × distance fraction; the metric itself is the largest session window of shifts (≤ 1 s between shifts, ≤ 5 s window) — not the lifetime sum, which is what it was before June 2021. Good is ≤ 0.1, needs improvement ≤ 0.25, poor > 0.25, at the 75th percentile of field dataPerformance metrics captured from real users, not lab tests.. Only viewport-visible shifts count; shifts within 500 ms of a discrete input are excluded (scrolling isn’t). The causes are unsized images/video/ads/iframesHTML element that displays one webpage inside another — how embeds work./ embeds, web fonts, and content injected above existing content; the fixes are reserving space,font-display/size-adjust, andtransform-only animation. The trap to avoid: LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. (lab) routinely reads near-0 because it doesn’t interact with the page or run the full lifecycle — field data (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.) is what Google actually measures.
What CLS measures
Google’s framing: “Cumulative Layout Shift (CLS) is a stable Core Web Vital metric. It’s an important, user-centric metric for measuring visual stability because it helps quantify how often users experience unexpected layout shifts.” The operative word is unexpected — content that moves on its own, not because the user did something.
It sits in the Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. trio with Largest Contentful PaintLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. (loading) and Interaction to Next PaintInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. (responsiveness). Where LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. are timed in milliseconds, CLS is the odd one out: a unitless ratio score. That trips people up constantly. A CLS of 0.05 is not 50 ms. It has no time unit at all.
The formula: impact × distance
Per shift, Google defines it as:
layout shift score = impact fraction × distance fraction- Impact fraction “measures how unstable elements impact the viewport area between two frames” — the combined visible area the moving elements occupied (before and after), as a share of the viewport.
- Distance fraction is “the greatest horizontal or vertical distance any unstable element has moved in the frame divided by the viewport’s largest dimension (width or height, whichever is greater).”
Both dimensions matter independently. A small element that travels across most of
the screen and a large element that barely nudges can score very differently.
web.dev’s worked example: an impact fraction of 0.75 and a distance fraction of
0.25 give a layout shift score of 0.1875.
Three cards form the equation. Impact fraction is 0.75: the visible viewport area affected between two frames. Distance fraction is 0.25: the farthest movement divided by the viewport's largest dimension. Multiplying them produces a unitless individual layout-shift score of 0.1875. CLS ultimately keeps the largest session-window total, not a lifetime sum of every shift.
© Patrick Stox LLC · CC BY 4.0 ·
Session windows: the part everyone gets wrong
Here’s the single most-misstated fact about CLS, and the one I most want you to take away. CLS is not the sum of all shifts over the page’s lifetime. It used to be — that changed in June 2021.
Today: “CLS measures the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifecycle of a page.” A burst is a session window: “one or more individual layout shifts occur in rapid succession with less than 1-second in between each shift and a maximum of 5 seconds for the total window duration.” CLS is the score of the largest such window — not the sum, not the average.
Evidence for this claim CLS uses the largest session window of unexpected layout shifts, with gaps under one second and a maximum five-second window; recent discrete input can exclude a shift. Scope: Current CLS session-window and recent-input rules. Confidence: high · Verified: web.dev: Cumulative Layout ShiftWhy the change? The old sum-everything definition quietly punished long-lived pages. A single-page app or an infinite-scroll feed accumulated more CLS just by existing longer, even if each individual shift was tiny and well-spaced. The Chrome Speed Metrics team moved to a maximum session window to stop penalizing duration, and chose maximum over average to avoid a perverse outcome where fixing a small, secondary shift could make your score worse. When the change rolled out, no origin got a worse score, most saw no change, and a slice of slow-UI and infinite-scroll pages improved. If you read an older post that still says “sum of all shifts,” it’s out of date.
What counts — and what doesn’t
Three exclusions decide what actually lands in your score:
- Below the fold doesn’t count. Only shifts of content visible in the current viewport are scored. A shift at the bottom of a long page that the user never scrolls to has no impact. Practically, this means fixing in-viewport shifts is almost always higher ROI than chasing shifts way down the page.
- User-initiated shifts get a 500 ms pass. “Layout shifts that occur within
500 milliseconds of user input will have the
hadRecentInputflag set, so they can be excluded from calculations.” Google’s stance: shifts “that occur in response to user interactions… are generally fine, as long as the shift occurs close enough to the interaction that the relationship is clear to the user.” Open an accordion, expand a menu — that movement is expected, so it’s forgiven. - But scrolling is not a free pass. The 500 ms exclusion only applies to discrete events — tap, click, keypress. Continuous gestures (scrolling, pinch-zoom) do not trigger the exclusion window. If content shifts while someone scrolls, that still counts. This distinction is wrong in a lot of coverage; get it right.
Thresholds, and where the score comes from
“To provide a good user experience, sites should strive to have a CLS score of 0.1 or less,” measured at “the 75th percentile of page loads, segmented across mobile and desktop devices.” The full bands:
- Good: ≤ 0.1
- Needs improvement: 0.1 – 0.25
- Poor: > 0.25
The 0.1 line isn’t arbitrary. Google’s user research foundA 302 (\"Found\") is a temporary redirect: it forwards users to a new URL while telling search engines the original URL should stay in the index. It's a weak canonicalization signal, not the zero-equity dead end of SEO folklore. that “levels of shift from 0.15 and higher were consistently perceived as disruptive, while shifts of 0.1 and lower were noticeable but not excessively disruptive.” They landed on 0.1 rather than something stricter partly because third-party embeds (ads, social) so commonly cause shifts that a tighter bar would be impractical for the real web.
The “75th percentile of field data” part is load-bearing, which brings us to the biggest measurement trap.
Lab vs. field: why the numbers disagree
This is where most people get burned. LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. and other lab tools often report a CLS near 0.0 while field data — and Google — show something much worse. The gap isn’t either tool being dishonest; it’s scope. A lab run is a single, short, scripted page load: it doesn’t scroll, doesn’t click, and doesn’t stick around, so it captures initial-load shifts only. Field data (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.) aggregates real visits across many users, devices, and navigations over a rolling window, and CLS is defined over the entire page lifecycle — menus opening, lazy content loading as the user scrolls, late ads filling in, however long the session runs. A short lab run structurally can’t see most of that.
So the practical rule is: use lab data to debug a specific shift, and field data to know your real score. Google ranks on field data from the Chrome User Experience Report (CrUX), surfaced in PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. and Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.. If Lighthouse reads 0.0 but PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. shows 0.18, treat the field number as the one that reflects your actual users — then go reproduce the shift in the lab by interacting with the page the way a real visitor would. Two more scope gaps worth knowing: most tools, including Lighthouse, don’t propagate iframe layout shifts up to the parent document’s score even though CrUX can reflect them, and RUM built on the Layout Instability API inherits that same iframe blind spot — so your own real-user monitoring can under-explain a CrUX number that looks worse than what your first-party attribution shows.
The common causes
In rough order of how often I see them:
- Images and video without dimensions. No reserved height means everything below jumps when the media loads.
- Ads, embeds, and iframes without reserved space. Ad networks serve dynamic sizes; embeds don’t announce their height before loading.
- Dynamically injected content above existing content. Cookie banners, notification bars, “related” widgets, late-loading promos — anything that pushes down what’s already on screen.
- Web fonts (FOIT/FOUT). When the custom font swaps in for the fallback, text reflows if their metrics differ.
- Animations on layout-triggering properties. Animating
top,left,margin,box-shadow, orbox-sizingforces the browser to re-lay-out the page on every frame.
The fixes
Each fix mirrors its cause:
- Images/video — reserve the space. Set
widthandheightattributes so the browser computes the aspect ratio and holds the box; pair withimg { height: auto; width: 100%; }for responsive behavior, or use the CSSaspect-ratioproperty. This is the single highest-leverage CLS fix on most sites. - Ads/embeds/iframes — reserve space too. Use
min-heightoraspect-ratioon the container; for ad slots, Google’s Publisher Tag guidance is blunt: “Setting a fixed height and width directly on the ad slotdivis the most effective way to do this.” For multi-size slots, reserve for the largest configured size. Push late-loading content lower so any residual shift is below the fold. - Dynamic content — don’t insert into the flow. Reserve a placeholder that matches the final size, or overlay the content instead of injecting it. Skeleton loaders only help if they match the final dimensions exactly — a skeleton even a few pixels shorter than the real content still shifts. Prefer user-triggered loads (“Load more”) over surprise insertions.
- Fonts — match the metrics.
font-display: optionalis the only value with effectively zero CLS risk;swapminimizes invisible text but can shift on the swap. Better still, use the CSS metric overrides —size-adjust,ascent-override,descent-override,line-gap-override— to size the fallback font to match the web font so the swap is seamless. Preload critical fonts. - Animations —
transformonly. Animate withtransform(translate, scale, rotate) instead oftop/left/margin. Transform-based animations are composited and don’t trigger layout, so they don’t shift anything.
How CLS fits into rankings (keep it in proportion)
CLS is one input to Google’s page experience signal. Google says Core Web Vitals are something its ranking systems use — but current Search documentation doesn’t publish an exact CLS weight, a tiebreaker rule, or a ranking guarantee, so treat any specific mechanism (including “it’s a tiebreaker”) as a working approximation, not a documented fact. My standing advice across everything I write about Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data.: get into the “good” band and move on. Most sites won’t see a meaningful ranking or business lift from grinding 0.08 down to 0.02, and a single score rarely explains a revenue or conversion outcome by itself. CLS is table stakes — you want to clear the bar, but it shouldn’t become the centerpiece of your SEO program at the expense of LCP, INP, or, frankly, your actual content.
Two operational notes that save a lot of confusion:
- CrUX lags ~28 days. It’s a rolling 28-day window, so a fix you ship today won’t fully register in PageSpeed Insights or Search Console for weeks. Don’t panic when the number doesn’t move the next morning.
- The attributed element is often not the root cause. The Layout Shift Attribution API tells you which element moved, but as web.dev notes, “it’s possible that these elements are only indirectly related to the ‘root cause’ of layout instability.” The text that jumped is usually the victim of an unsized image above it loading late — fix the cause, not the symptom. Work it as a timestamp-to-trigger loop: note the shift’s start time, then check what else changed in that same window — a network request finishing, an image or font arriving, a resize, or a class/style change — and treat the attributed node as a lead, not proof, until you’ve matched it to that trigger.
AI summary
A condensed take on the Advanced version:
- CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. = visual stability, the Core Web Vital for unexpected movement of visible content. It sits alongside Largest Contentful PaintLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and Interaction to Next PaintInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good..
- It’s a unitless score, not a time. 0.05 is a ratio, not 50 ms.
- Per-shift formula:
impact fraction × distance fraction— how much of the viewport moved, times how far, relative to the viewport’s largest dimension. - The metric is the largest session window (≤ 1 s between shifts, ≤ 5 s total window) — not the lifetime sum. That changed in June 2021 to stop penalizing long-lived/SPA pages; maximum was chosen over average.
- Thresholds (75th percentile, field dataPerformance metrics captured from real users, not lab tests.): Good ≤ 0.1 · Needs improvement ≤ 0.25 · Poor > 0.25.
- Exclusions: below-the-fold shifts don’t count; shifts within 500 ms of a discrete input (tap/click/key) are excluded — scrolling is not exempt.
- Causes: unsized images/video/ads/iframesHTML element that displays one webpage inside another — how embeds work./embeds; injected content above existing content; web fonts; animating layout-triggering properties.
- Fixes: set
width/heightoraspect-ratio; reserve space for dynamic content (skeletons must match exact dimensions);font-display+size-adjust; animate withtransformonly. - Lab ≠ field. LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. often reads near-0 because it doesn’t interact with the page or run the full lifecycle; field data (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program./PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking.) is what Google ranks on. Iframe shifts usually don’t propagate to the parent score in lab or RUM tools.
- Ranking: one input Google says its ranking systems use within page experience — no documented weight or tiebreaker rule, so get to “good” and move on rather than chasing a specific mechanism. CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. lags ~28 days; the attributed element is often not the root cause.
Official documentation
Primary-source documentation from Google / the Chrome team.
Core CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. docs
- Cumulative Layout Shift (CLS) — the canonical definition, the impact × distance formula, session windows, thresholds, and the
hadRecentInputexclusion (Milica Mihajlija and Philip Walton). - Optimize Cumulative Layout Shift — the official causes-and-fixes guide: images, ads/embeds, injected content, fonts, animations.
- Debug layout shifts — finding shifts in Chrome DevTools, the Layout Shift Regions overlay, and the LayoutShiftAttribution API (Katie Hempenius and Barry Pollard).
Background and measurement
- Evolving Cumulative Layout Shift in web tooling — why the metric moved from sum-of-all-shifts to the largest session window in June 2021 (Annie Sullivan and Hongbo Song, Chrome Speed Metrics Team).
- How the Core Web Vitals metrics thresholds were defined — the user research and achievability data behind the 0.1 / 0.25 bands.
- Getting started with measuring Web Vitals — lab vs. field dataPerformance metrics captured from real users, not lab tests., and why lab CLS can read artificially low.
- Font best practices —
font-display, metric overrides, and preloading for font-related CLS.
Ads and Search
- Minimize layout shift — Google Publisher Tag guidance for reserving ad-slot space.
- Understanding Core Web Vitals and Google Search results — how CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. (including CLS) factor into Search.
Quotes from the source
On-the-record statements from Google / the Chrome team. Each link is a deep link that jumps to the quoted passage on the source page.
Google — what CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. is
- “Cumulative Layout Shift (CLS) is a stable Core Web Vital metric. It’s an important, user-centric metric for measuring visual stability because it helps quantify how often users experience unexpected layout shifts.” Jump to quote
- “CLS measures the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifecycle of a page.” Jump to quote
Google — the formula
- “layout shift score = impact fraction * distance fraction” Jump to quote
- “The impact fraction measures how unstable elements impact the viewport area between two frames.” Jump to quote
- “The distance fraction is the greatest horizontal or vertical distance any unstable element has moved in the frame divided by the viewport’s largest dimension (width or height, whichever is greater).” Jump to quote
Google — session window
- “A burst of layout shifts, known as a session window, is when one or more individual layout shifts occur in rapid succession with less than 1-second in between each shift and a maximum of 5 seconds for the total window duration.” Jump to quote
Google — thresholds and user input
- “To provide a good user experience, sites should strive to have a CLS score of 0.1 or less… a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.” Jump to quote
- “Layout shifts that occur within 500 milliseconds of user input will have the
hadRecentInputflag set, so they can be excluded from calculations.” Jump to quote - “Layout shifts that occur in response to user interactions (such as clicking or tapping a link, pressing a button, or typing in a search box) are generally fine, as long as the shift occurs close enough to the interaction that the relationship is clear to the user.” Jump to quote
Google — how the thresholds were chosen
- “levels of shift from 0.15 and higher were consistently perceived as disruptive, while shifts of 0.1 and lower were noticeable but not excessively disruptive.” Jump to quote
Google — reserving ad-slot space
- “Setting a fixed height and width directly on the ad slot
divis the most effective way to do this.” Jump to quote
Google — the attributed element vs. the root cause
- “elements listed as sources are the elements that shifted during the layout shift. However, it’s possible that these elements are only indirectly related to the ‘root cause’ of layout instability.” Jump to quote
CLS causes → fixes checklist
Work top-down; the first two items fix the majority of real-world CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good..
- Every
<img>and<video>haswidth+height(or a CSSaspect-ratio), withimg { height: auto; width: 100%; }for responsive layouts. - Ad slots, iframesHTML element that displays one webpage inside another — how embeds work., and embeds reserve space via
min-height/aspect-ratio; multi-size ad slots reserve for the largest configured size. - Late-loading content sits below the fold where possible, so any residual shift doesn’t count.
- Injected content (cookie banners, promos, “related” widgets) is overlaid or pre-reserved — not inserted above existing content.
- Skeleton placeholders match the final content’s exact dimensions (a few pixels off still shifts).
- Web fonts use
font-display: optionalwhere acceptable, orswapplussize-adjust/ascent-overrideto match fallback metrics; critical fonts are preloaded. - Animations use
transformonly — nevertop,left,margin,box-shadow, orbox-sizing. - You’ve checked the score in field data (PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. / Search Console / CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.), not just LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal..
- You’ve reproduced shifts by interacting with the page — scrolling, opening menus, triggering lazy loadsLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. — not just on initial load.
- Ad/iframe shifts verified in the field (lab tools often don’t propagate them to the parent score).
CLS cheat sheet
The numbers
| Band | CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. (75th percentile, field) |
|---|---|
| Good | ≤ 0.1 |
| Needs improvement | > 0.1 to 0.25 |
| Poor | > 0.25 |
The definition, in one line
layout shift score = impact fraction × distance fraction(per shift).- CLS = the largest session window of shifts — ≤ 1 s between shifts, ≤ 5 s total window. Not the lifetime sum (that was pre-June-2021).
- It’s a unitless score, not a time.
What’s excluded
- Shifts below the fold (not in the current viewport).
- Shifts within 500 ms of a discrete input (tap/click/keypress) —
hadRecentInput. - Not excluded: shifts during scrolling or pinch (continuous gestures).
Causes → fixes
| Cause | Fix |
|---|---|
| Image/video without dimensions | width + height attrs, or CSS aspect-ratio |
| Ads / iframesHTML element that displays one webpage inside another — how embeds work. / embeds | Reserve space: min-height / aspect-ratio; fixed size on ad-slot div |
| Injected content above the fold | Overlay or pre-reserve; trigger via user action |
| Web fonts (FOITFont loading is how a browser fetches, applies, and renders custom web fonts — and specifically what it shows while the font file downloads. Those choices, controlled mainly by the CSS font-display property, directly affect two Core Web Vitals: LCP and CLS./FOUT) | font-display: optional/swap + size-adjust metric overrides; preloadResource hints are <link> elements (or equivalent HTTP Link headers) that tell the browser to do network work — DNS lookups, connection setup, or fetching a resource — earlier than it would discover the need on its own. The main ones are dns-prefetch, preconnect, preload, modulepreload, and prefetch. |
| Layout-triggering animation | Animate with transform, not top/left/margin |
Measurement gotchas
- LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. (lab) often reads ~0 — it doesn’t interact with the page or run the full lifecycle. CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. / PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. (field) is what Google ranks on.
- CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. lags ~28 days — fixes take weeks to show.
- Iframe shifts usually don’t propagate to the parent score in lab tools.
- The attributed element is the one that moved, not necessarily the root cause.
Patrick's relevant free tools
- Page Speed Test & Core Web Vitals Checker — One sentence tells you whether a page passes Core Web Vitals and what to fix first — real Chrome user data (CrUX) with a Lighthouse lab fallback, mobile and desktop side by side, loudly-labeled data sources, and prioritized diagnostic fixes. Plus a bulk origin scorecard with CSV export.
- Hosting Checker — Find a domain's public IP network, CDN or edge platform, DNS and mail-host evidence, and response transfer facts without pretending a proxy reveals the origin.
- Core Web Vitals History & Competitor Comparison — Chart 40 weeks of real-Chrome-user Core Web Vitals — p75 LCP, INP, CLS, FCP, and TTFB from the Chrome UX Report — and compare up to 5 origins or URLs on one chart. Plus a competitor Leaderboard that ranks curated groups of SEO and page-speed tools on each metric. Pass/fail scorecards, mobile vs desktop, shareable links, CSV export.
Tools for measuring and debugging CLS
Field dataPerformance metrics captured from real users, not lab tests. (what Google ranks on)
- PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. — CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. field CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. at page and origin level, plus a LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. lab run side by side. The fastest way to see the lab-vs-field gap for yourself.
- Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. — Core Web Vitals reportThe Google Search Console report (under Experience) that shows how your indexed URLs perform on the Core Web Vitals — LCP, INP, and CLS — using real-user field data from CrUX, grouped by device, status, and clusters of similar-performing URLs. — per-URL-group field CLS across your whole site, grouped by status.
- CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. (Chrome User Experience Report) — the underlying field dataset; explore history via the CrUX dashboards / BigQuery.
Lab data (for debugging)
- Chrome DevTools — Performance panelThe Performance panel is Chrome DevTools' built-in, local profiler for recording and analyzing how a page loads and runs — CPU, main-thread work, rendering, network, and live Core Web Vitals. The recorded trace is local, lab data from your own browser — not what Googlebot sees — though the panel can optionally show real-user CrUX field data alongside it. — record a trace, then read the Layout Shifts track; clicking a shift highlights the elements that moved and shows the shift score. Live Metrics shows CLS update in real time as you interact.
- Layout Shift Regions overlay — DevTools → Settings → More tools → RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. → Layout Shift Regions. Reload and shifting areas flash so you can see them.
- LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. — quick lab CLS, but remember it only captures initial-load shifts.
- WebPageTestWebPageTest is a free, open-source, lab-based website performance testing tool — created by Patrick Meenan in 2008 and acquired by Catchpoint in 2020 — that runs pages on real browsers from distributed locations and produces deep diagnostics (waterfalls, filmstrips, connection views, Core Web Vitals). It's a diagnostic tool, not a Google ranking input. — lab CLS with filmstrip and trace.
RUM (your own field data)
- web-vitals JavaScript library —
onCLS()reports real-user CLS from your own visitors (~2 KB); the most accurate picture of what people actually experience. - PerformanceObserver (
layout-shift) — the raw API the library wraps, plus the LayoutShiftAttributionsourcesfor which elements moved.
How the tools themselves score
A live example of the metric this page describes — well-known page-speed and monitoring services ranked on their own real-user mobile CLS (Chrome UX Report field data):
Which CLS fix should you make first?
What is causing the visible layout shift?
CLS mistakes that hide the real problem
Treating a clean Lighthouse run as proof
LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. may finish before a consent banner, ad, or interaction-driven shift occurs. Use the lab run to debug, but check CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. or your own real-user monitoring before declaring the problem fixed.
Fixing only the element DevTools says moved
The shifted element is often the victim. A late-loading item above it may be the cause. Replay the trace and inspect what entered or resized immediately before the movement.
Reserving space with a guessed fixed height
A fixed placeholder can create a second shift when responsive content is taller or shorter. Use intrinsic dimensions or aspect-ratio where the content’s proportions are known.
Animating layout properties
Changing top, left, or margins can move surrounding content. Animate with transform when the effect does not need to change document flow.
Diagnose a CLS problem by symptom
Field CLS is poor but the lab score is near zero
Likely cause: the shift happens after interaction, during a longer session, or only for a subset of users. Fix: reproduce the real journey while recording the Performance panelThe Performance panel is Chrome DevTools' built-in, local profiler for recording and analyzing how a page loads and runs — CPU, main-thread work, rendering, network, and live Core Web Vitals. The recorded trace is local, lab data from your own browser — not what Googlebot sees — though the panel can optionally show real-user CrUX field data alongside it., then add web-vitals attribution in real-user monitoring. Confirm: the offending interaction and shifted element appear in the trace or RUM record.
Text jumps when the custom font arrives
Likely cause: the fallback and web font use different metrics. Fix: preloadResource hints are <link> elements (or equivalent HTTP Link headers) that tell the browser to do network work — DNS lookups, connection setup, or fetching a resource — earlier than it would discover the need on its own. The main ones are dns-prefetch, preconnect, preload, modulepreload, and prefetch. only the critical font where appropriate and match the fallback with font metric overrides. Confirm: replay with cache disabled and verify that the Layout Shifts track no longer records the swap.
A banner or ad pushes the page down
Likely cause: the slot has no reserved dimensions before its content arrives. Fix: allocate a stable container or place the message where it does not displace visible content. Confirm: throttle the load and watch the slot retain its footprint.
CLS improves in testing but not in PageSpeed Insights
Likely cause: CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. is a rolling field dataset rather than an immediate deployment check. Fix: verify the change in lab and RUM first, then wait for the field window to turn over. Confirm: your own post-release field distribution improves before the public CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. aggregate follows.
Capture layout shifts in the browser
Paste this into the DevTools Console before reproducing the problem. It ignores shifts tied to recent user input and prints the score plus the elements the browser attributed.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.hadRecentInput) continue;
console.table({
value: entry.value,
time: Math.round(entry.startTime),
elements: entry.sources?.map((source) => source.node),
});
}
});
observer.observe({ type: 'layout-shift', buffered: true });The attributed node is a lead, not automatic proof of the cause. Compare its timestamp with network requests, font loads, and DOM insertions in the same trace.
Prove a CLS fix worked
Reserved-space test
Test to run: disable the cache, throttle the connection, reload, and record the Performance panelThe Performance panel is Chrome DevTools' built-in, local profiler for recording and analyzing how a page loads and runs — CPU, main-thread work, rendering, network, and live Core Web Vitals. The recorded trace is local, lab data from your own browser — not what Googlebot sees — though the panel can optionally show real-user CrUX field data alongside it. Layout Shifts track. Expected result: the media or embed keeps the same footprint before and after it loads. Failure interpretation: its container still depends on late content for dimensions. Monitoring window: immediate in the trace. Rollback trigger: the new placeholder creates clipping, excess blank space, or a new shift at a responsive breakpoint.
Font-swap test
Test to run: reload with cache disabled while watching text and the Layout Shifts track. Expected result: the fallback-to-web-font transition creates no measurable shift. Failure interpretation: fallback metrics still differ or the critical font arrives too late. Monitoring window: immediate in repeated lab runs. Rollback trigger: the change hides text longer or makes the final typography materially wrong.
Field confirmation
Test to run: compare post-release onCLS() data for the changed template with its pre-release baseline, then watch CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.. Expected result: the real-user p75 improves without a worse tail on key journeys. Failure interpretation: another late or interaction-driven source remains. Monitoring window: RUM as traffic arrives; CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. over its 28-day rolling window. Rollback trigger: CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. or user interaction errors worsen consistently after release.
CLS metrics worth tracking
Real-user CLS at p75
Metric: the 75th-percentile CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. for each important template and device class. What it tells you: whether most visits meet the visual-stability target. How to pull it: CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program., PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking., or web-vitals RUM. Benchmark / realistic range: good is 0.1 or less; 0.1–0.25 needs improvement; above 0.25 is poor. Cadence: monitor releases in RUM and review the rolling field trend monthly.
Poor-visit rate
Metric: the share of real visits with CLS above 0.25. What it tells you: whether an acceptable p75 hides a damaging tail. How to pull it: bucket your onCLS() events by template and journey. Benchmark / realistic range: establish a site baseline and drive the poor bucket down; traffic mix makes a universal target misleading. Cadence: weekly for high-traffic templates and after layout releases.
Shift attribution by cause
Metric: layout-shift entries grouped by element or component. What it tells you: which recurring implementation owns the most instability. How to pull it: the attribution build of web-vitals or PerformanceObserver. Benchmark / realistic range: no universal range; compare components by total impact and affected visits. Cadence: review with each template or component release.
Resources worth your time
Official, in depth
- Cumulative Layout Shift (CLS) — the canonical reference.
- Optimize Cumulative Layout Shift — the official fix guide.
- Debug layout shifts — the DevTools workflow.
- Evolving Cumulative Layout Shift in web tooling — the June 2021 session-window change, explained by the team that made it.
From practitioners
- How To Fix Cumulative Layout Shift (CLS) Issues — Barry Pollard, Smashing Magazine. Goes deep on font descriptors and the “the element that shifted isn’t the root cause” problem.
- Cumulative Layout Shift in Practice — Nic Jansma (Cloudflare; W3C Web Performance WG). The best write-up of measurement nuances: iframeHTML element that displays one webpage inside another — how embeds work. attribution gaps, the 5-element attribution sample, and tool-to-tool discrepancies.
- Measure and Optimize Cumulative Layout Shift — DebugBear.
- The Almost-Complete Guide to Cumulative Layout Shift — Jess Peck. Thorough treatment of edge cases including SPA navigation shifts and continuous-gesture exclusion nuances.
- Layout shift culprits — Chrome DevTools documentation on the CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. culprit insight panel — useful companion to the web.dev debug guide.
- How to Fix Cumulative Layout Shift (CLS) — Kinsta. Practical CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms.-focused walkthrough covering WordPress-specific causes (gallery images, late-loading widgets, cookie banners).
- Layout Instability API — WICG spec. The underlying browser API CLS is built on; useful if you’re building custom RUM or need exact
hadRecentInputsemantics.
Where it fits in my own work
- CLS shows up as a “table stakes” metric across my Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. coverage — track it, get into the good band, and keep it in proportion against LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good., INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., and your content. Google doesn’t publish an exact CLS weight or tiebreaker rule, so it’s one input to watch, not the game.
Stats worth citing
- The 0.1 threshold is grounded in perception research. Google’s user studies foundA 302 (\"Found\") is a temporary redirect: it forwards users to a new URL while telling search engines the original URL should stay in the index. It's a weak canonicalization signal, not the zero-equity dead end of SEO folklore. shifts of 0.15 and higher were consistently perceived as disruptive, while 0.1 and lower were noticeable but not excessively so. Source
- CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. is the easiest Core Web Vital to pass. Across my enterprise audits the pattern is consistent: a large majority of sites clear the CLS bar (often ~80%+), yet only a little over half pass all three vitals together — CLS is rarely the one holding you back.
- The June 2021 change helped, never hurt. When CLS moved to the largest session window, no origin received a worse score, most saw no change, and a slice of infinite-scroll and slow-UI pages improved. Source
- Unsized media is still everywhere. Industry crawls (Web Almanac) consistently find a large share of pages shipping images without explicit dimensions — the single most common CLS cause, and the easiest to fix.
- 72% of websites globally now achieve good CLS (2025 Web Almanac / HTTP Archive data), making CLS the easiest Core Web Vital to pass — yet 62% of mobile pages still ship at least one image without explicit dimensions, the single most common cause. Source: HTTP Archive / Web Almanac
- Business impact: Rakuten 24 reported a 53.37% increase in revenue per visitor for users experiencing low CLS versus high CLS — a frequently cited case study, not evidence that a given CLS number causes a specific business outcome on other sites. Source: corewebvitals.io case studies
Videos
- Google Search Central / Chrome for Developers (YouTube) — the Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. and Debug layout shifts walkthroughs, including DevTools demos of the Layout Shifts track and the Layout Shift Regions overlay. Channel
Test yourself: Cumulative Layout Shift
Five quick questions on measuring and fixing visual instability. Pick an answer for each, then check.
CLS
Cumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.
Related: Core Web Vitals, LCP, INP
CLS
Cumulative Layout ShiftCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. (CLS) is the Core Web Vital for visual stability — it measures how much visible content unexpectedly moves while a page is in use. It’s a unitless score, not a time: a CLS of 0.05 is a ratio, it doesn’t mean 50 ms of anything.
Each individual shift is scored as impact fraction × distance fraction — how much of the viewport the moving elements touched, multiplied by how far they moved relative to the viewport’s largest dimension. Despite the name, CLS is not the sum of every shift across the page’s lifetime. Since June 2021 it’s the score of the largest session window: a burst of shifts with less than 1 second between consecutive shifts and a maximum window of 5 seconds. The old “sum of all shifts” definition is still floating around in older posts — it’s outdated.
The “good” target is ≤ 0.1, with 0.1–0.25 “needs improvement” and > 0.25 “poor,” judged at the 75th percentile of real users in field dataPerformance metrics captured from real users, not lab tests. (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.). Only shifts of content already visible in the viewport count, and shifts within 500 ms of a discrete user input (tap, click, keypress) are treated as expected and excluded — scrolling is not.
Common culprits: images, video, ads, iframesHTML element that displays one webpage inside another — how embeds work., and embeds without dimensions; web fonts swapping in; content injected above what’s already on screen; and animating layout-triggering CSS properties. The fixes mirror the causes — set width/height or aspect-ratio, reserve space for dynamic content, tune font-display, and animate with transform instead of top/left.
Related: Core Web Vitals, LCP, INP
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 17, 2026.
Editorial summary and recorded change details.Summary
Bounded the lab-vs-field and ranking claims to what current sources document, and added a root-cause diagnostic loop for debugging shifts.
Change details
-
Replaced the categorical 'Lighthouse lies' framing with a scope-based explanation (lifecycle length, interaction, iframe/RUM attribution) of why lab and field CLS numbers diverge.
-
Removed the flat 'CLS is a tiebreaker' ranking claim in favor of what Google's Search documentation actually states (ranking systems use Core Web Vitals; no published weight or tiebreaker rule), and softened the Rakuten revenue stat so it isn't read as single-score causality.
-
Added a timestamp-to-trigger diagnostic loop to the root-cause debugging guidance, tying the Layout Shift Attribution API's shifted node back to the actual trigger (network, image/font, resize, style change).
Full comparison unavailable — no prior snapshot was archived for this revision.