Cumulative Layout Shift, or CLS, measures how much visible content moves around unexpectedly while a page loads. It is a unitless score, and Google's documented threshold for "good" is 0.1 or less. This guide is written for the developer or technical founder staring at a failing score, and for the growth lead who has to brief that work to someone else. It covers what the score counts, which shifts are excluded, the six things that cause almost every failure on a B2B marketing site, a four-step workflow that ends with a named element, and the point at which you should stop.
The short version
- Most movement you notice never counts. Only unexpected shifts score, and anything within 500 milliseconds of a user interaction is excluded outright.
- CLS is unitless:
0.1or less is good, above0.25is poor, measured at the 75th percentile of real visits.- Field data is the verdict. A clean Lighthouse run means nothing if the Chrome User Experience Report says the page fails.
- On a marketing site the worst offenders are rarely images. They are the consent banner and a hero that gets replaced after first paint.
- Every fix is one idea applied to a different element: reserve the space before the thing arrives.
What is Cumulative Layout Shift, and what counts as a good score?
CLS is the score of the single worst burst of unexpected layout shift on a page, not the total of everything that moved. Google's web.dev reference on Cumulative Layout Shift defines it as a measure of the largest burst of layout shift scores for every unexpected shift that occurs during the entire lifecycle of a page. The score has no unit. Lower is better, and zero means nothing moved.
The bands Google publishes:
| CLS score | Verdict | What it feels like |
|---|---|---|
0.1 or less | Good | The page settles. Nothing jumps under the cursor. |
Above 0.1 up to 0.25 | Needs improvement | Noticeable movement, usually one late element pushing things down. |
Above 0.25 | Poor | The reader loses their place, or clicks the wrong thing. |
Those thresholds are evaluated at the 75th percentile of page loads, segmented by device type. That percentile is the part teams misread most often: your least stable quarter of visits sets the number, so the phone on a patchy connection decides your score, not the laptop on your desk. Fix mobile first, since that is where late-loading banners do the most damage and it is the version Google indexes. Our mobile SEO guide covers testing what Google actually sees on a phone.
Two mechanics are worth knowing, because they explain scores that otherwise look impossible.
How an individual shift is scored: web.dev gives the formula as layout shift score = impact fraction * distance fraction. The impact fraction is the share of the viewport occupied by the elements that moved, and the distance fraction is the greatest distance any of them travelled, as a fraction of the viewport's larger dimension. A badge that moves two pixels barely registers. A hero band that shoves the whole page down is expensive on both terms at once.
How the shifts are grouped: Chrome collects shifts into session windows. A window stays open while shifts keep arriving less than 1 second apart, up to a maximum window length of 5 seconds. Your CLS is the score of the largest window, not the sum of all of them. This is why a page with one bad moment and a dozen tiny ones is judged on the bad moment, and why fixing the loudest offender often moves the score more than tidying up five small ones.
Does CLS actually affect rankings?
Yes, but as a tiebreaker rather than a lever. Google states plainly in its page experience documentation that Core Web Vitals are used by its ranking systems, that there is no single page-experience signal, and that Search always seeks to show the most relevant content even when the page experience is sub-par. A stable page will not rescue one that fails to answer the query.
Where it earns its weight is at the margin, between two pages that are genuinely comparable. Our guide to Core Web Vitals covers the three-metric system, the field-versus-lab split, and where Largest Contentful Paint and Interaction to Next Paint fit. This article stays on CLS.
The stronger argument for fixing it has nothing to do with search. A page that moves under a reader's finger costs you the click you were trying to earn. On a pricing page or a demo form, that is a conversion problem before it is ever a ranking problem.
Which layout shifts count, and which do not?
Only unexpected ones. Shifts that occur within 500 milliseconds of a user interaction are excluded from the score, because content moving in response to a tap or a click is what the reader asked for. Chrome marks those entries with hadRecentInput set to true and leaves them out of the calculation.
That single rule retires a large share of the problems teams chase. An accordion opening does not count. A mobile menu expanding does not count. Neither do transforms: an element animated with CSS transform does not trigger layout, so a hover state that scales a card is invisible to CLS even though it visibly moves.
Three exclusions worth being precise about, because each one is regularly misattributed:
- Continuous interactions are not covered: scrolling, dragging, and pinch-zoom do not count as recent input, so a shift that happens during a scroll still scores.
- The 500 millisecond window is a budget, not a blanket: web.dev's advice for content that takes longer than that to arrive is to reserve its space inside the window, so the later insertion costs you nothing.
- Animations that change layout still count: animating
heightortopmoves the elements around it. Animatingtransformdoes not.
Before you spend a sprint on a shift, check that it is actually being counted. Plenty of visible movement is free.
What actually causes CLS on a SaaS marketing site?
Six things, and they are not the six on a generic list. Every explainer names images, ads, and fonts, which is accurate for a publisher and misleading for a B2B marketing site that runs no display advertising. In our implementation work the consent banner and a hero swapped by an A/B test account for more failing scores on marketing sites than unsized images do. Images are the textbook answer. They are usually not the one hurting you.
1. Media without reserved dimensions: an image, video, or iframe that arrives without the browser knowing its size gets laid out at zero height, then reflows everything below it. This is still the easiest cause to eliminate, because the fix is an attribute. Set width and height on every raster image and let CSS handle the rendered size.
<img src="/hero.webp" width="1200" height="630" alt="Product dashboard">
img {
height: auto;
width: 100%;
}
Modern browsers derive an aspect-ratio from those two attributes and reserve the box before the file downloads. For elements where you cannot know the intrinsic size, set the ratio yourself with aspect-ratio, or give the container a min-height. Formats, compression, and lazy loading are a separate discipline, and our image SEO guide covers those.
2. The cookie or consent banner: this is the one that quietly fails marketing sites. A consent script loads after first paint, injects a bar at the top or bottom of the document flow, and pushes everything below it. Because it fires for every first-time visitor and never for you, it is invisible during development and universal in field data. Render it as a fixed overlay outside the flow, or reserve its exact height in the initial layout.
.consent-banner {
position: fixed;
inset-inline: 0;
bottom: 0;
z-index: 100;
}
3. A/B tests and personalization that swap the hero after paint: an experimentation script that rewrites the headline, the subhead, or the entire hero block after the page has rendered produces a shift on exactly the element with the largest impact fraction. The two workable fixes are opposites. Either decide the variant before first paint, so nothing is drawn twice, or reserve the height of the taller variant so neither version moves the page. What does not work is an asynchronous swap with a fade, which hides the effect from you and not from the score.
4. Review badges, announcement bars, and third-party widgets: embedded G2 and Capterra badges, trust seals, status bars, chat launchers, and scheduling widgets all arrive late, and most of them inject their own markup. Any of them placed in the document flow will shift what follows. Wrap each in a fixed-size container sized to the rendered widget, and keep anything that cannot be sized out of the flow entirely.
5. Web fonts that swap: a fallback font renders first, the custom font arrives, and every line of text reflows because the two have different metrics. The damage scales with how much text sits above the fold, which on a marketing page is most of it. Preload the fonts you actually use above the fold and control the swap behavior.
<link rel="preload" as="font" href="/fonts/inter.woff2" type="font/woff2" crossorigin>
@font-face {
font-family: "Inter";
src: url("/fonts/inter.woff2") format("woff2");
font-display: optional;
}
font-display: optional is the strictest setting: if the font is not ready almost immediately, the browser keeps the fallback for that page view and no swap happens. If you need the brand font to appear and can accept a swap, match the fallback's metrics to the real font instead, using the size-adjust, ascent-override, descent-override, and line-gap-override descriptors that web.dev's guide to optimizing CLS documents.
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 107%;
ascent-override: 90%;
}
Compute those percentages for your own font pairing rather than copying the illustrative values above. On Next.js, next/font self-hosts the font files and generates a metric-matched fallback automatically through its adjustFontFallback option, which is on by default for Google fonts. Our Next.js SEO guide covers where next/image and next/font help and where they still leave work to do.
6. Content injected above what the reader is already looking at: announcement bars, geo-targeted notices, free-trial countdowns, and cookie strips added at the top of the document after load. This is the most expensive shape of shift there is, because everything on the page moves at once. web.dev's rule is blunt and correct: avoid inserting new content without a user interaction, and it names the pop-in at the top of the viewport as the case that does the damage.
How do you find the element that is shifting?
Four steps, in this order. The order matters, because steps one and two answer different questions, and teams routinely skip the first one and then optimize something that was never failing.
Step 1. Confirm the failure in field data: open the Core Web Vitals report in Search Console, or run the URL through PageSpeed Insights and read the field section at the top, not the Lighthouse score below it. Field data comes from the Chrome User Experience Report and is the only verdict that counts. If it puts the page inside 0.1, there is nothing to fix. Check mobile separately from desktop.
Step 2. Reproduce it with the shift regions overlay: in Chrome DevTools, open the Command Menu, run "Show Rendering", and enable the Layout Shift Regions checkbox. Chrome then briefly highlights every shifting area in purple as it happens. Reload with the cache disabled and, critically, with your consent state cleared, because the banner that is wrecking your score will not appear on a repeat visit. Watching one load with this on usually identifies the culprit in a single pass.
Step 3. Name the node in the Performance panel: record a page load in the DevTools Performance panel and look at the Layout Shifts track. Individual shifts appear as diamonds inside a cluster, sized by magnitude. Click the largest one, and the Summary panel gives you the start time, the shift score, and the elements that moved. That is the named node the whole exercise is for. Chrome's DevTools documentation on rendering performance covers the overlay and where the controls live.
Step 4. Match it to the offender list and apply the fix: once you have the element, the cause is nearly always one of the six above, and the fix follows from the cause rather than from the element. Confirm mechanically in the lab the same day, then wait for field data for the verdict.
Two conditions hide from a normal local test, so reproduce both deliberately: throttle to a slow connection, so late resources actually arrive late, and use a fresh profile or an incognito window, so consent, personalization, and returning-visitor logic behave the way they do for a stranger.
What is the fix for each cause, and who owns it?
Most of this table is developer work, but two rows are not, and knowing which is which saves a ticket that would otherwise sit in a backlog for a month.
| Cause | The fix | Owner and verification |
|---|---|---|
| Image, video, or iframe without dimensions | Set width and height, or an explicit aspect-ratio on the container | Developer. Confirm the element reserves space with JavaScript disabled. |
| Cookie or consent banner | Render as a fixed overlay outside the document flow, or reserve its exact height | Marketer, in the consent tool's own layout settings. Verify with consent cleared. |
| A/B test or personalization swapping the hero | Decide the variant before first paint, or reserve the height of the taller variant | Developer with the growth owner. Verify with the experiment forced on. |
| Review badges, chat, and scheduling widgets | Fixed-size wrapper sized to the rendered embed, or keep it out of the flow | Developer. Verify on a throttled connection. |
| Web font swap | Preload above-the-fold fonts, then font-display: optional or a metric-matched fallback | Developer. Verify with the font request blocked in DevTools. |
| Announcement bar injected at the top | Render it server-side in the initial HTML, or drop it | Marketer's call, developer's implementation. Verify on a first visit. |
The consent banner row is the one worth escalating first. It usually needs no engineering at all, because most consent platforms offer an overlay layout as a configuration option, and switching it is a ten-minute change that a marketer can make without a deploy.
Why does my CLS differ between Lighthouse and Search Console?
Because they measure different things, and only one of them is the verdict. Search Console reports field data from the Chrome User Experience Report, aggregated from real visitors on a rolling 28-day window. Lighthouse runs one simulated load in a controlled environment. Our Core Web Vitals guide sets out the full field-versus-lab comparison, so the short version here is: field decides, lab explains.
For CLS the gap between the two is usually wider than for the other metrics, and the reasons are structural. A lab run measures shifts during page load only, while field data captures the whole lifecycle, including everything a real reader triggers by scrolling. A single automated load also runs with no consent state, no experiment assignment, and often a warm cache, which is precisely the configuration in which your three worst offenders do not fire.
So a clean Lighthouse score is not evidence that CLS is fine. It is evidence that CLS is fine under conditions no real visitor experiences. And because field data moves on a 28-day window, a fix you shipped last week will not surface in Search Console for weeks. Confirm the fix in the lab the day you ship it, then check the field number a month later.
When should you stop optimizing CLS?
When field data puts you inside 0.1. That is the whole answer. Taking a score from 0.08 to 0.04 changes nothing about how the page ranks or how it feels, because the threshold is a pass or a fail and you have already passed it. In my experience, teams spend more time on an already-good CLS score than on the poor LCP sitting next to it, largely because CLS is the most visible of the three metrics and therefore the most satisfying to chase.
Redirect the effort deliberately. If one vital is failing and CLS is not it, that failing metric is your work. If all three pass and rankings are still flat, the bottleneck is relevance, depth, or authority, and no amount of stability work will touch it. Our SEO services exist for that kind of diagnosis, and our technical SEO checklist shows where the vitals check sits inside a wider technical pass.
One case deserves the opposite response. When field data shows CLS in the poor band on a page that converts, fix it this week, because real visitors are losing their place on a page you are paying to send traffic to.
Where should you start this week?
The habit worth building is a monthly read of the Core Web Vitals report in Search Console, because CLS does not decay gradually. It regresses in a single deployment, on the day someone adds a banner, a badge, or a tag, and then sits there for the 28 days it takes field data to tell you. A monthly check catches that while the change responsible is still recent enough to identify. Building the reservation habit into your components is cheaper still, which is why our guide to an SEO-friendly website build treats stability as a build decision rather than a cleanup task, and why it shapes how we approach web development.
This week, open PageSpeed Insights on your homepage and your highest-traffic landing page, and read the field data at the top of the report, on the mobile segment. If CLS is poor on either, run the four steps above with your consent state cleared, and start with the banner.
Need an SEO-Friendly Website?
We design and develop high-performance websites built for users, search engines, and conversions.
Start Your Website ProjectFrequently Asked Questions
What is a good CLS score?
Google's documented good threshold is 0.1 or less, measured at the 75th percentile of real visits. Between 0.1 and 0.25 needs improvement, and anything above 0.25 is poor. The 75th percentile matters more than the number itself: it means your slowest and least stable quarter of visitors sets your score, so optimize for a mid-range phone on a mediocre connection rather than for the laptop on your desk.
How do you fix cumulative layout shift?
Every fix is the same idea applied to a different element: reserve the space before the thing arrives. Set explicit width and height or an aspect ratio on images, video and iframes. Give consent banners, announcement bars and embedded badges a fixed-height container, or render them as overlays outside the document flow. Preload key fonts and control the swap. Never insert content above what the reader is already looking at.
Do cookie banners hurt CLS?
Frequently, and on marketing sites they are one of the two most common causes. A banner that loads after first paint and pushes the page down registers as a shift for every visitor. The fix is to render it as a fixed overlay that sits above the page rather than inside the flow, or to reserve its exact height in the initial layout. Test with a cleared consent state, because the banner will not appear on your own repeat visits.
Why does my CLS score differ between Lighthouse and Search Console?
They measure different things. Search Console reports field data from the Chrome User Experience Report, aggregated from real visitors over a rolling 28-day window, and that is what counts for page experience. Lighthouse runs one simulated load in a controlled environment, which is useful for diagnosis but is not the verdict. A single lab run also misses shifts caused by consent banners, personalization and third-party scripts that behave differently for real users.
Does every layout shift count against my score?
No. Shifts that happen within 500 milliseconds of a user interaction are excluded, because moving content in response to a click or tap is expected behavior rather than a defect. An accordion opening or a menu expanding does not count. Only unexpected shifts, the ones that happen while the reader is doing nothing, contribute to the score.

Anshuman Sinha
AI SEO Specialist, GrowthHasten
Anshuman Sinha is an AI SEO Specialist and Computer Science Engineer with over three years of experience in SEO and five years in web development. He specializes in Technical SEO, AI Search Optimization (AEO and GEO), SaaS SEO, and building high-performance websites with modern technologies.
View profile



