TL;DR, Quick Answer
7 min readCumulative Layout Shift scores each unexpected movement as impact fraction multiplied by distance fraction. The browser groups shifts into session windows that close after a 1 second gap or 5 seconds of total duration, and reports the highest-scoring window as the page's CLS. Nothing is summed across the whole page, which is why the name misleads almost everyone who reads it.
What is Cumulative Layout Shift (CLS)?
Chrome measures Cumulative Layout Shift as the largest burst of unexpected layout movement during a page's lifetime, where each individual shift scores impact fraction multiplied by distance fraction and the highest-scoring burst becomes the page's CLS. The metric exists because content that jumps under a reader's finger costs them the tap they were about to make. Two numbers decide every score: how much of the viewport moved, and how far it went.
The name causes most of the confusion. "Cumulative" describes what happens inside one burst, not across the page, so forty small shifts spread over three minutes can score better than two shifts half a second apart.
How is a layout shift score calculated?
The formula published by the Chrome team on web.dev, checked on 8 September 2026, is a single multiplication:
layout shift score = impact fraction × distance fraction
The impact fraction is the union of the visible area an unstable element occupied in the previous frame and the area it occupies in the current frame, divided by the total viewport area. The distance fraction is the greatest horizontal or vertical distance any unstable element moved in that frame, divided by the viewport's largest dimension, width or height, whichever is greater.
Work one shift end to end. Take a mobile viewport 400px wide and 800px tall, so the largest dimension is 800px. A full-width article heading and its opening paragraph occupy the top 400px, which is half the viewport. A consent banner then injects above them and pushes the block down by 160px.
| Input | Value | Where it comes from |
|---|---|---|
| Viewport | 400 × 800 px | 320,000 px total area |
| Element before the shift | y 0 to 400 | 160,000 px visible |
| Element after the shift | y 160 to 560 | 160,000 px visible |
| Union of both frames | y 0 to 560 | 224,000 px |
| Impact fraction | 0.7 | 224,000 ÷ 320,000 |
| Distance moved | 160 px | banner height |
| Distance fraction | 0.2 | 160 ÷ 800 |
0.7 × 0.2 = 0.14
One banner produced 0.14, which already sits in the "needs improvement" band. The two fractions gate each other: a tiny element scores low even when it travels the full screen, and a full-viewport block scores high even when it travels 20px.
Why is CLS not the sum of every shift?
CLS reports the single highest-scoring session window, not a running total. A session window opens at the first shift and stays open while shifts keep arriving less than 1 second apart, up to a maximum window duration of 5 seconds. When a gap of 1 second or more passes, or the window hits 5 seconds, that window closes and the next shift starts a fresh one. The browser scores each window separately and reports the largest.
Continue the example above. The 0.14 banner shift lands at 1.2s. A web font swaps at 1.5s and reflows a paragraph for 0.03. The gap is 300ms, so both belong to one window worth 0.17. A lazy-loaded embed then shifts the footer by 0.05 at 4.0s, which is 2.5 seconds after the last shift, so it opens its own window.
| Window | Shifts | Window score |
|---|---|---|
| 1 (1.2s to 1.5s) | 0.14 banner, 0.03 font swap | 0.17 |
| 2 (4.0s) | 0.05 embed | 0.05 |
The page's CLS is 0.17, the larger of the two, not 0.22. Chasing the sum sends teams to the wrong shift: find the window that scored highest and fix what is inside it.
What counts as an unexpected layout shift?
A shift counts as unexpected unless it follows a user interaction within 500 milliseconds. Chrome flags any shift that occurred close behind a tap, click or key press with hadRecentInput, and those shifts are excluded from the score, because a reader who opened an accordion expects the content below it to move.
That 500ms rule is a design lever, not an implementation detail. A "Load more" button costs nothing, and the same content injected by a timer costs whatever the formula says.

What causes Cumulative Layout Shift?
Four sources produce almost every shift worth fixing, and each has a fix that removes the shift instead of shrinking it.
Flowsery
Start FREE Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
| Cause | What the browser does | Fix |
|---|---|---|
| Images and video without dimensions | Reserves zero height, then reflows when the file arrives | Set width and height attributes, or reserve the box with CSS aspect-ratio |
| Ads, iframes and third-party embeds | Sizes the slot only after the third party responds | Reserve the slot with min-height or aspect-ratio, sized from the dimensions that slot has served before |
| Injected banners, notices and skeletons | Inserts a node into the document flow and pushes everything below it | Reserve the space up front, render it outside the flow as an overlay, or insert it behind a user action |
| Web fonts | Swaps a fallback face for the web font, changing text metrics mid-render | Use font-display: optional, match the fallback with size-adjust and the font override descriptors, and preload the critical face |
The pattern underneath all four: reserve the box before the content exists. A browser that already knows the height of a slot has nothing to reflow when the slot fills.
Why does lab CLS differ from field CLS?
Lab CLS covers page load only, and field CLS covers the entire page lifecycle. Lighthouse loads a URL on a fixed device profile, records shifts inside its measurement window, then stops. Real people scroll past that window, trigger lazy-loaded images, dismiss a banner, open a menu, and every shift after Lighthouse's cutoff still counts in the field.
Viewport and network add a second gap. The distance fraction divides by the viewport's largest dimension, so the same 160px banner scores differently on a phone than on a desktop, and a fast lab connection delivers a slot's contents before the shift happens at all, hiding a defect that fires every time on a slow network. Fix regressions in the lab, then judge the result on field data from real visits, where the thresholds for all three vitals sit in one table.

How do you find the shift that caused a bad CLS?
Pair the field score with a recording of the session that produced it, so the burst becomes something you watch instead of something you infer. A p75 of 0.28 tells you the page fails; it does not tell you that a consent banner injects 160px above the fold for visitors whose IP resolves to the EU.
Flowsery ships one script under 10 KB, cookie-free and EU-hosted, and applies no sampling, so the score comes from every session instead of a subset. It records the sessions alongside the timings, groups matching ones into a single issue ranked by how many users hit it, and sends that issue to Slack, Linear or Jira with the replay and steps to reproduce attached.
CLS is one of three Core Web Vitals, and each fails for its own reasons. Largest Contentful Paint covers render timing, Interaction to Next Paint covers responsiveness, and the Core Web Vitals overview explains why a page has to pass all three at once.
Frequently asked questions
What is a good CLS score?
0.1 or less at the 75th percentile is good, 0.1 to 0.25 needs improvement, and above 0.25 is poor, per the Chrome team's thresholds on web.dev as of September 2026. The percentile is calculated separately for mobile and desktop, so a page can pass on desktop and fail on phones. What counts as a good CLS breaks down how the p75 is assembled.
Does CLS have a unit?
No. Both inputs to the formula are fractions of the viewport, so multiplying them produces a unitless number. That is why 0.1 means the same thing on a 400px phone and a 2560px monitor: the metric normalises against the screen it happened on.
Do shifts below the fold count toward CLS?
Only movement of content visible in the viewport at the time of the shift contributes to the impact fraction. An element that reflows 4000px down the page while the reader sits at the top adds nothing. It starts counting the moment the reader scrolls it into view and it moves again.
Why did my CLS get worse after I added a skeleton loader?
A skeleton that does not match the final content's height shifts the page twice instead of once: first when the skeleton appears, then again when the real content replaces it with different dimensions. Size the skeleton to the box the content will occupy, or the placeholder becomes the defect.
Can an animation cause a layout shift?
Animating properties that trigger layout, such as top, left, width or height, moves surrounding content and scores as a shift. Animating transform does not, because the compositor moves the painted layer without re-running layout. Move animations to transform and opacity and the shifts disappear.
Does CLS still accumulate after the page finishes loading?
Yes. The browser watches for shifts through the whole page lifecycle, so a banner that injects 30 seconds in, or an image that lazy-loads on scroll, opens a new session window and can become the page's reported score. This is the main reason a clean Lighthouse run coexists with a failing field score.
How long does a CLS session window stay open?
A session window opens at the first shift and keeps collecting shifts that land less than 1 second apart, up to a hard cap of 5 seconds. A gap of 1 second or a total duration of 5 seconds closes it, and the next shift starts a new window. Chrome scores every window on the page and reports only the highest one as CLS.
Does clicking a button before a shift stop it from counting toward CLS?
A shift is excluded from CLS if it happens within 500 milliseconds of a tap, click or key press, a flag Chrome records as hadRecentInput. A "Load more" button that expands content right after a click costs nothing, while the same content injected by a timer scores under the formula. The rule exists because a reader who just opened an accordion expects what sits below it to move.
Flowsery
Start FREE Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
Why does the same layout shift score differently on mobile than on desktop?
The distance fraction divides how far an element moved by the viewport's largest dimension, so a fixed pixel shift is a bigger fraction of a phone screen than a wider desktop one. The 160px banner push in the walkthrough above scores 0.2 on an 800px-tall viewport and would score lower on a taller desktop screen. Field CLS compounds this by calculating the p75 separately for mobile and desktop, so the same defect can pass on one and fail on the other.
What is the fastest fix for image-related layout shift?
Set width and height attributes on images and video, or reserve the box with the CSS aspect-ratio property, so the browser holds the space before the file arrives. Images without dimensions reserve zero height by default, then reflow the page the moment the file loads. Reserving the box removes the shift instead of just shrinking it.
Was This Article Helpful?
Let us know what you think!
See us more often in Google
One click marks Flowsery as a preferred source, so our articles sit higher in your Top Stories, AI Mode, and AI Overviews.
Before you go...
Flowsery
Revenue-first analytics for your website
Track every visitor, source, and conversion in real time. Simple, powerful, and cookie-free.
Real-time dashboard
Goal tracking
Cookie-free tracking
Related Glossary Terms


How Interaction to Next Paint Scores Your Worst Click
Chrome scores Interaction to Next Paint on a page's worst interaction, timing input delay, processing and presentation delay to the next painted frame.


What the Numbers Say About Average Bounce Rate by Industry
Nine tracked industries return a documented average bounce rate by industry ranging from 35.76% to 48.38%, sourced from Databox data dated September 2024.


Working Through the Average Order Value Formula Step by Step
The average order value formula divides revenue by orders, and a single discount code or return policy can quietly distort every number a team reports.


Reading a Retention Curve Starts With Cohort Analysis
A retention curve only makes sense once cohort analysis groups users by a shared start date, since one average hides the pattern a cohort table reveals.


Where Drop-off Really Happens in a Conversion Funnel
Step conversion and overall conversion answer different questions about a conversion funnel, and the gap between them shows exactly where drop-off happens.


Two Numbers Hide Behind One Drop-off Rate
Every funnel produces two drop-off rate numbers, one per step and one end to end, and teams quote them interchangeably. A worked table separates them.
Related Articles


The Setup Choices Behind Every Funnel Analysis
Three setup choices decide what funnel analysis reports: step sequencing, the conversion window, and whether the funnel counts users or sessions.


Five Ways to Calculate Net Revenue Retention From One Dataset
One net revenue retention formula, five defensible variants: the same cohort returns 84.0%, 104.5%, 108.3%, 109.5% or 110.3% depending on window and base.


How to Calculate A/B Test Sample Size Before You Launch
Before launching a test, a/b test sample size determines whether the result you see is signal or noise, and the formula needs three numbers set in advance.

