What is Cumulative Layout Shift (CLS)?

Cumulative Layout Shift measures unexpected movement of visible elements during a page's lifetime, scored as impact fraction times distance fraction. Good is 0.1 or less. It is caused almost entirely by images without dimensions, injected banners, late-loading webfonts and dynamically inserted content.

Last updated 2026-07-28

How is the CLS score actually calculated?

Each individual shift scores impact fraction — how much of the viewport moved — multiplied by distance fraction, how far it moved, and CLS reports the worst burst of those shifts rather than the sum of everything that ever moved. A burst, formally a session window, is a run of shifts each less than one second apart, capped at five seconds in total.

That windowing matters for long pages. An infinite-scroll feed that shifts slightly every few seconds is not punished cumulatively for the whole session; only its worst five-second stretch counts. A single catastrophic reflow at load, on the other hand, is counted in full.

The score is unitless, which is why a good CLS of 0.1 has no seconds or pixels attached — and why it is the odd one out among the three Core Web Vitals, the other two of which are measured in time. A shift that moves half the viewport by a fifth of its height scores roughly 0.1 on its own — so one badly behaved banner is enough to fail the threshold.

What causes layout shift, and what fixes each cause?

Four things cause almost all layout shift: images and embeds without reserved space, ads and iframes that size themselves after loading, injected content such as cookie bars and promo banners, and webfonts that swap in at a different size to the fallback. Each has a specific fix, and the table below pairs them up.

The common thread is that the browser did not know how much room something needed until it arrived. Every fix below is a way of telling it in advance.

CauseFix
Images and video without dimensionsAlways set width and height attributes, or use aspect-ratio in CSS
Ads, embeds and iframesReserve the space with a min-height container before the content loads
Injected content — banners, cookie barsReserve space, or overlay instead of pushing content down
Webfonts causing FOUT/FOITPreload the font and use font-display: optional or swap with a metrics-matched fallback

What is the single highest-value fix?

Setting width and height attributes on every image resolves the majority of CLS problems on most sites. Modern browsers compute the aspect ratio from those two numbers and reserve the correct space before the file arrives, so nothing below the image moves when it finally loads.

The attributes do not control the display size — CSS still does that, and a responsive width: 100% rule works exactly as before. They are purely a hint about proportions, which is why adding them is safe on almost any existing template.

Since this means touching every <img> tag in the template anyway, it is the natural moment to also check that each one carries descriptive alt text — the same audit pass catches both.

Reserve the space
<!-- Causes shift: browser cannot reserve space -->
<img src="/hero.jpg" alt="Report overview">

<!-- No shift: aspect ratio known before load -->
<img src="/hero.jpg" alt="Report overview" width="1200" height="630">

/* Or in CSS */
.hero { aspect-ratio: 1200 / 630; width: 100%; }

Does clicking or scrolling count as a layout shift?

No — shifts that happen within 500 milliseconds of a discrete user input such as a tap, click or keypress are excluded, so opening an accordion or expanding a menu costs you nothing. Only unexpected movement counts against CLS.

Scrolling and pinch-zoom are the exception worth knowing: they are continuous gestures rather than discrete inputs, so they do not earn a shift that exclusion. Content that reflows during a scroll — a sticky header that resizes, or images that size themselves as they enter the viewport — is still counted.

This is also why animating layout properties is risky and animating transform is not. A transform moves pixels without changing layout, so it produces no shift at all.

Why does CLS look fine locally but bad in Search Console?

Because a lab run loads the page once, quickly, from a single location — without the cookie banner triggered by a visitor's region, the ad that fills three seconds late, or the personalised block that only logged-in users see. Field CLS routinely exceeds lab CLS for exactly those reasons.

When the two disagree, believe Search Console and go looking for conditional or third-party content. Reproduce it by loading the page from a region that triggers the consent banner, with an ad blocker disabled, on a throttled connection that gives late-arriving content time to be noticed.

If a whole template is affected rather than one URL, crawling the site and comparing CLS across pages is faster than testing URLs by hand — repetition down the report is the signature of a template problem. The same logic applies to the other loading metric, Largest Contentful Paint, which usually fails for template reasons too.

Frequently asked questions

What is a good CLS score?

0.1 or less at the 75th percentile. Between 0.1 and 0.25 needs improvement; above 0.25 is poor.

Do width and height attributes control image size?

No — CSS still controls display size. They tell the browser the aspect ratio so it can reserve the right space before the image downloads.

Does a cookie banner hurt CLS?

If it pushes content down when it appears, yes. Overlay it above the content or reserve its space in the initial layout.

Is CLS the sum of every shift on the page?

No. It reports the largest burst of shifts within a session window — shifts less than a second apart, capped at five seconds — not the total for the whole visit.

Related guides