Skip to main content
All fixes

Page speed, redirects, Core Web Vitals

Fix CLS too high: stop layout shifts above 0.1

Cumulative Layout Shift above 0.1 fails Core Web Vitals. Find the shifting elements in DevTools and reserve space for images, fonts, and ads so content stops jumping.

What's happening

Cumulative Layout Shift quantifies how much visible content moves around during page load. Each shift is scored as impact fraction times distance fraction, summed across all unexpected shifts in the largest 5-second window. Good CLS is below 0.1, needs improvement is 0.1 to 0.25, and poor is anything above 0.25. Unlike LCP and INP, CLS keeps accumulating after initial load — a late-arriving ad slot or a font swap can ruin an otherwise stable page.

Chrome DevTools' Performance panel highlights every layout shift with a red marker on the timeline, plus the moved DOM nodes in the Summary tab. The Layout Shift Regions overlay (Rendering tab → Layout Shift Regions) flashes blue rectangles over shifting elements in real time, which makes diagnosis trivial. The Lighthouse "Avoid large layout shifts" audit lists the worst offenders ranked by score contribution.

Most CLS issues fall into four buckets: images without width and height attributes, web fonts swapping in with different metrics (FOIT/FOUT), dynamically injected content above existing content (cookie banners, hero carousels), and ad slots that resize themselves after a network call. The fix is almost always to reserve space ahead of time.

Why it matters

CLS is a Core Web Vitals ranking signal. Pages that fail at the 75th percentile lose mobile SERP positions, particularly in news and e-commerce verticals where layout shift is most common. The page experience signal can't lift mediocre content, but it actively demotes pages that flunk the thresholds.

User-facing impact is severe: misclicks on the wrong button, lost form input when a dialog jumps, frustration that reads as "this site feels broken." Studies from Indeed and others have shown CLS improvements driving session length up by 5-10 percent. On mobile, where buttons are small and thumbs commit fast, a shift of even 50 pixels frequently leads to accidental taps.

Common causes

  • tags missing width and height attributes, so the browser allocates zero space until the image loads.
  • @font-face without size-adjust or font-display: optional causes a metric mismatch when the web font swaps in.
  • Cookie banners, GDPR notices, and promo bars injected at the top of the document push existing content down.
  • Ad slots without a reserved min-height resize when the creative arrives.
  • Embedded iframes (YouTube, Twitter) without an aspect-ratio container.
  • CSS animations that affect layout properties (width, height, top, left) instead of transform/opacity.
  • Late-loading components that render placeholder-then-real-content with different dimensions.

Detect this on your site

Run a quick scan with the Speed Test. The tool surfaces this exact issue with the records and context needed to apply the fix below.

Open Speed Test

How to fix it

  1. 1

    Enable Layout Shift Regions in DevTools

    Open Chrome DevTools, hit Cmd+Shift+P, type "Show Rendering" and toggle "Layout Shift Regions". Reload the page and watch for blue flashes — each one is a shift. Note the timing and the elements involved before you start fixing.

  2. 2

    Add explicit width and height to every image

    Set width and height attributes on every and. Modern browsers compute aspect-ratio from these attributes and reserve the correct space, even with responsive CSS like width: 100%; height: auto. next/image enforces this automatically when you provide width and height props.

  3. 3

    Use font-display: optional or size-adjust for web fonts

    @font-face { font-display: optional; } prevents font swap if the font isn't ready in 100ms. For higher-fidelity matching, use the Font fallback metrics override (size-adjust, ascent-override) generated by Capsize or fontpie to make the fallback match the web font's metrics exactly.

  4. 4

    Reserve space for ads and embeds with aspect-ratio

    Wrap ad slots and iframe embeds in a container with aspect-ratio: 16/9 (or whatever the slot dimension is) and min-height. The slot occupies its space from the first paint, so the creative can't push content around when it arrives.

  5. 5

    Render banners at the bottom or with fixed positioning

    If your cookie banner must appear above existing content, use position: fixed with bottom: 0 so it overlays instead of pushing. If it must push, reserve top padding equal to the banner height so the shift is zero.

  6. 6

    Animate only transform and opacity

    Replace any CSS transitions or @keyframes that animate width, height, top, left, margin, or padding with transform-based equivalents (translate, scale). Layout-affecting animations count toward CLS — composited animations don't.

  7. 7

    Verify in field data with web-vitals.js

    Ship web-vitals.js's onCLS hook to your analytics so you see per-route CLS in production. Lab CLS often misses interaction-driven shifts (modal opens, infinite scroll) — only field measurements catch these.

Example

<!-- Reserve space for image -->
<img src="/hero.jpg" width="1600" height="900" alt="" style="width:100%;height:auto">

<!-- Reserve space for video embed -->
<div style="aspect-ratio:16/9;width:100%">
  <iframe src="https://www.youtube.com/embed/..." style="width:100%;height:100%"></iframe>
</div>

<!-- Font with reduced layout shift -->
<style>
@font-face {
  font-family: "Inter";
  src: url("/inter.woff2") format("woff2");
  font-display: optional;
  size-adjust: 107%;
  ascent-override: 90%;
}
</style>

Reserve dimensions for images, embeds, and font fallbacks.

Frequently asked

aspect-ratio is in every evergreen browser since Safari 15 and has 96%+ global support. For older browsers the padding-bottom hack still works as a fallback inside an @supports block.

Late-arriving images and fonts give the browser more time to paint the placeholder then more time to shift when the real asset lands. Reserving space ahead of time makes the metric independent of network speed.

Shifts within 500ms of a user input (click tap keypress) are excluded from the score. Shifts caused by scrolling resizing or autonomous network responses still count.

Related fixes