What is CLS, how is it calculated, and how do you fix it?
What does CLS measure?
CLS stands for Cumulative Layout Shift. It is one of the stable Core Web Vitals, and it tracks how often visible content moves when the reader did not expect it. Typical examples are a paragraph jumping down while someone reads it, or a button moving at the moment a user taps, so they hit the wrong thing.
web.dev sets the thresholds like this:
- Good: 0.1 or less
- Needs improvement: above 0.1 and up to 0.25
- Poor: above 0.25
Google recommends judging the score at the 75th percentile of page loads, with mobile and desktop measured separately. That way most visitors get a stable page, not only the average one.
How is CLS calculated?
Every unexpected shift gets its own layout shift score:
layout shift score = impact fraction x distance fractionThe impact fraction is the combined visible area of the unstable elements across the previous frame and the current frame, as a share of the viewport. The distance fraction is the greatest distance any unstable element moved, horizontally or vertically, divided by the largest dimension of the viewport.
Shifts are then grouped into session windows. A shift joins the current window if it happens less than one second after the previous shift, and a window can last no longer than five seconds. The CLS value is the session window with the highest total, not the sum of every shift on the page.
Shifts that happen within 500 milliseconds of a discrete input, such as a tap, click or keypress, are flagged with hadRecentInput and left out, because the user caused them. Scrolling, dragging and pinch zoom do not count as recent input.
What is the difference between CLS and LCP?
Both are Core Web Vitals, but they measure different things. LCP, Largest Contentful Paint, measures loading. It reports when the largest image, text block or video visible in the viewport finished rendering, counted from when the user first navigated to the page. A good LCP is 2.5 seconds or less, and anything over 4 seconds is poor.
CLS measures visual stability for the whole life of the page, not only the load. A page can load quickly and still shift badly when a late banner appears, so it is worth checking both at the 75th percentile, split by device type.
How do you find what is causing layout shifts?
web.dev suggests starting with PageSpeed Insights. If the field CLS from the Chrome User Experience Report is close to the lab CLS from Lighthouse, the shift probably happens during load. A large gap suggests shifts that happen after load, often after a user interacts.
In Chrome DevTools, the Performance panel has a Layout Shifts track that groups shifts into clusters, and the size of each diamond is proportional to the size of the shift. Lighthouse audits also list images without dimensions. For real visitor data, the web-vitals JavaScript library has attribution functions that collect extra detail about layout shifts in the field. Lab tools only capture shifts during page load, so they can understate what users actually see.
The performance tools on AI Web Page SEO can also be used to check layout stability on a page: performance tools.
How to fix cumulative layout shift
The common thread in Google's guidance is to reserve space for anything that arrives late, so nothing below it has to move.
- Images: set
widthandheightattributes, or use the CSSaspect-ratioproperty, so the browser can reserve the box before the file arrives. Keep everysrcsetcandidate at the same aspect ratio. - Ads, embeds and iframes: reserve space with
min-heightoraspect-ratio, using the smallest likely size, and keep a placeholder if no ad fills the slot. - Injected content such as banners and forms: use a placeholder or skeleton, or overlay the content so it does not push the page down.
- Animations: animate with
transformrather than properties such astoporleft, which trigger layout. - Web fonts: use
font-display: optionalor a closely matched fallback font, adjusted with descriptors such assize-adjust, and preload critical fonts. - Back and forward navigation: make pages eligible for the back/forward cache, so returning visitors get the page restored without repeating load shifts.
A simple image example looks like this:
<img src="hero.jpg" width="1200" height="600" alt="Product photo">After changes, check the field data again, because CLS in Search Console and the Chrome User Experience Report is based on real visits rather than a single test.
Sources
- web.dev: Cumulative Layout Shift (CLS)
- web.dev: Optimize Cumulative Layout Shift
- web.dev: Largest Contentful Paint (LCP)
Frequently asked questions
Do layout shifts caused by a click count towards CLS?
No. web.dev explains that shifts happening within 500 milliseconds of a discrete user input, such as a tap, click or keypress, are flagged with hadRecentInput and excluded from the score, because the user expected them. Scrolling, dragging and pinch zoom are not treated as recent input, so shifts during those actions can still count. Content that expands slowly after a click, beyond that 500 millisecond window, can also add to CLS.
Why is my lab CLS lower than the score real users get?
Lab tools such as Lighthouse only record shifts during page load in a test environment. Real visitors scroll, click and stay on the page, and later shifts are counted in field data from the Chrome User Experience Report and Search Console. web.dev also notes that shifts inside iframes cannot be measured through web APIs but are included in that field data, so the two numbers often differ.