← Back to blogSEO & Performance

Cumulative Layout Shift (CLS): The Complete Guide

Cumulative Layout Shift Guide

Cumulative Layout Shift (CLS) is a Core Web Vitals metric that measures visual stability — how much the content of a page jumps around during loading. Google rates a CLS score under 0.1 as good, between 0.1 and 0.25 as needs improvement, and above 0.25 as poor. The most common causes are images without dimensions, dynamically injected content, web fonts, and ads. The fixes are mostly structural: reserve space for everything that loads asynchronously.

What CLS Actually Measures

If you have ever tried to tap a button on your phone and the button moved at the last second because an ad loaded above it, that is the user experience CLS measures. It is the irritation of content jumping around, the misclick that takes you to a page you did not want, the moment of distrust when the page rearranges itself in front of you.

The metric is calculated by multiplying the impact fraction (how much of the viewport shifted) by the distance fraction (how far it moved), then summing across all unexpected layout shifts on the page. Shifts that happen within 500ms of a user interaction are excluded — those are intentional, not surprises.

The result is a unitless number. Below 0.1, the page feels stable. Between 0.1 and 0.25, visitors notice but tolerate. Above 0.25, the page feels broken. CLS became a Core Web Vitals ranking signal in 2021 and is now scored alongside Largest Contentful Paint and INP in the broader Core Web Vitals report.

Why Layout Shift Happens

Images Without Dimensions

The most common cause of bad CLS. An <img> tag without explicit width and height attributes renders at zero height initially. The browser reserves no space. When the image data downloads, the browser inflates the element, and everything below it shifts down. On a slow connection, this happens dramatically.

The fix is simple: always include width and height attributes (or set the aspect-ratio CSS property). The browser uses those values to reserve space before the image loads, so the layout never shifts. Modern frameworks like Next.js Image, Astro Image, and Framer’s image component handle this automatically.

Web Fonts (FOUT and FOIT)

When a custom font loads, text reflows. A heading rendered in the system font might wrap differently than the same heading in the custom font. The reflow shifts everything below the heading. This is FOUT — Flash of Unstyled Text — and the source of subtle but real CLS.

The fix is to use font-display: swap combined with size-adjusted fallback fonts. Tools like Fontaine and Capsize generate fallback font metrics that match the custom font closely enough that the swap does not cause visible reflow. The website typography guide covers font loading strategies in depth.

Dynamically Injected Content

Content that loads after the initial render — banners, A/B test variants, cookie consent overlays, hero rotators — pushes content down when it appears. If a banner injects at the top of the page after 800ms, everything below it shifts by the banner height. Newsletters love this pattern. Visitors hate it.

The fix is to reserve space. Either render the banner placeholder server-side with min-height, or position the banner with absolute positioning so it overlays content rather than displacing it. Cookie consent dialogs should always overlay, never push.

Ads

Ad networks are the worst offenders for CLS. Display ads load asynchronously, often into containers without fixed heights, and shove content around the moment they render. The dominant fix is to fix the ad container height with min-height or aspect-ratio, even if that means reserving space for an ad that does not load. The trade-off is real (a sliver of empty space is sometimes better than the ad), but better empty space than a CLS score in the red.

Embedded Videos and iFrames

YouTube embeds, Calendly widgets, and similar iframe-based embeds often render as zero-height placeholders, then resize to their final dimensions on load. Reserve space with explicit width and height (or aspect-ratio) on the iframe element.

How to Measure CLS

PageSpeed Insights

The fastest CLS check is at pagespeed.web.dev. Paste a URL, get a report. The diagnostics section calls out specific elements contributing to CLS, with screenshots of before and after the shift. This is the easiest way to identify which elements are jumping.

Chrome DevTools

The Performance tab in Chrome DevTools includes a “Layout Shifts” section that visualizes shifts as red overlays on the page screenshots. Record a load, scroll through the timeline, and you will see exactly which elements shifted and when.

Chrome’s Web Vitals extension shows live CLS readings as you browse. Useful for testing your own staging sites and seeing how shifts accumulate during real interaction.

Search Console Field Data

Google Search Console’s Core Web Vitals report shows real CLS data from Chrome users in the last 28 days, broken down by URL group. Field data is what Google uses for ranking, so this is the report that matters most for SEO.

How to Fix CLS

Always Set Image Dimensions

For every <img>, set width and height attributes. The browser uses these to compute the aspect ratio and reserves the right amount of space. Use aspect-ratio: 16 / 9 in CSS for responsive cases. Image components in Next.js, Astro, Framer, and most modern frameworks handle this without manual effort. The image optimization guide covers responsive image patterns.

Reserve Space for Async Content

For any content that loads after the initial render — ads, banners, video embeds, recommendation widgets — reserve space with min-height or aspect-ratio. The placeholder might be empty for a moment, but the layout will not jump.

Use Skeleton Loaders

For content fetched after page load (think dashboard rows, search results, news feed items), use skeleton loaders that match the final content’s dimensions. The shape of the page stays consistent; only the content within it changes.

Avoid Inserting Above Existing Content

The single most CLS-friendly principle: never insert content above content that is already rendered. Banners, notifications, and announcements should overlay or sit at the top of the document from the first paint, not slide in after.

Optimize Web Font Loading

Use font-display: swap on every @font-face. Pair custom fonts with size-adjusted fallback fonts using size-adjust and ascent-override. Tools like the npm package fontaine generate the right values automatically.

Animate Transforms, Not Layout

If you must animate the appearance of an element, use CSS transform and opacity rather than properties that affect layout (width, height, top, left). Transforms do not trigger layout shifts. The same animation that scores 0.18 with width transitions can score 0.00 with transform: scale().

CLS Pitfalls

Hero Carousels

A common CLS culprit on agency and ecommerce sites. The first slide is often a different height than subsequent slides, and the slide change triggers a layout shift. Fix the carousel container height to match the tallest slide, and use overflow: hidden to clip shorter slides.

Sticky Headers That Activate on Scroll

If a header changes from position: relative to position: sticky on scroll, the layout shifts. Either commit to sticky from the start, or use a fixed-height placeholder that absorbs the change.

Lazy-Loaded Above-the-Fold Images

Lazy loading is great for below-the-fold images. Above the fold, it backfires: the image starts at zero height (because dimensions are not set) and inflates after the lazy load triggers. The hero image should never be lazy-loaded. The website speed optimization guide covers when to lazy-load and when not to.

Self-Hosted Video Posters

Video elements without a poster image render at zero height until metadata loads. Set width, height, and a poster attribute on every video element.

CLS on Modern Frameworks

Next.js

The Next.js Image component sets width and height automatically and reserves space for every image. The font module (next/font/google) handles font loading with optimal settings out of the box. CLS on a stock Next.js project is usually well under 0.05 without manual tuning.

Framer

Framer’s image component handles dimensions and lazy loading automatically. CLS on Framer sites is generally good, with the exception of custom code components that bypass the platform’s optimizations. If you import third-party widgets via custom code, set explicit dimensions on the wrapper.

WordPress

WordPress is mixed. Modern themes built on the block editor handle dimensions correctly. Older themes (especially those with hand-coded loops) frequently render images without width and height attributes. Plugins like Smush, ShortPixel, and EWWW Image Optimizer can backfill dimensions automatically.

CLS and SEO

CLS is a Google ranking signal. The impact is moderate — a single bad CLS score will not destroy your rankings — but it compounds with other signals. A site with good CLS, good LCP, and good INP has a measurable advantage in mobile search over a competitor with similar content but worse vitals.

The 75th-percentile rule applies. If 75% of your real Chrome visitors over the last 28 days experienced under 0.1 CLS, you pass. The hardest part is that one bad page (a popular blog post with a broken layout, for example) can drag the site-level score below the threshold even if every other page is fine.

The Framer Websites team regularly audits sites for CLS as part of performance reviews. The fixes are usually mechanical — set dimensions, reserve space, swap fonts cleanly — and the impact on user experience is immediate.

Frequently Asked Questions

What is a good CLS score?

Under 0.1 is rated good by Google. Between 0.1 and 0.25 is needs improvement. Above 0.25 is poor. The score is the 75th percentile across real Chrome users in the last 28 days, so 75% of real visits must come in under the threshold to earn a passing grade.

How do I find which element is causing CLS?

Open Chrome DevTools, switch to the Performance tab, record a page load, and look at the Layout Shifts section. Shifts are highlighted with red overlays showing exactly which elements moved and how far. PageSpeed Insights also surfaces CLS-causing elements in its diagnostics.

Does lazy loading hurt CLS?

Only for above-the-fold images. Lazy-loading content below the fold is safe and often improves both CLS and LCP. Lazy-loading the hero image is a common mistake — the image starts at zero height and inflates when it loads, causing a shift. Eager-load anything visible on first paint.

Can I have a 0.0 CLS score?

Yes, and many static sites do. Reserve space for every image, video, ad, and async-loaded element. Avoid injecting content above existing content. Use size-adjusted font fallbacks. With those four habits, CLS scores under 0.05 are routine and 0.00 is achievable.

Ready to build your Framer website?

Book a free strategy call to discuss your project.