Lighthouse audit cumulative-layout-shift · Performance · Core Web Vital

Cumulative Layout Shift (CLS): what it is and how to fix it

View raw .md for LLMs / your notes

CLS measures unexpected layout movement during page load. It's one of Google's three Core Web Vitals, a stable, predictable page ranks better and converts better.

TL;DR

What CLS measures

Every time a visible element jumps to a new position without user input, CLS increases. The metric is impact fraction × distance fraction, summed over the page session. A button that moves down 100px right before the user clicks counts heavily; a tiny shift in a far corner barely registers.

What's a good CLS score?

RangeVerdict
≤ 0.1Good
0.1–0.25Needs improvement
> 0.25Poor

Most common causes

  1. Images without dimensions, the browser can't reserve space until it downloads them
  2. Web fonts swapping (FOUT/FOIT) and reflowing text
  3. Ads, embeds, iframes without reserved containers
  4. Dynamically injected content above existing content (banners, cookie notices, A/B test variants)
  5. Animations using top/left instead of transform

Five concrete fixes

1. Always set width and height on images

<!-- WRONG: no dimensions, layout shifts when image loads -->
<img src="/photo.jpg" alt="…" />

<!-- RIGHT: dimensions reserve the aspect ratio -->
<img src="/photo.jpg" width="1200" height="800" alt="…" />

Modern browsers compute aspect-ratio automatically from these attributes, the slot is reserved before download finishes.

2. Reserve space for ads, embeds, iframes

.ad-slot {
  min-height: 250px; /* reserve whatever the typical ad height is */
  width: 100%;
}

If you don't know the ad height in advance, use a placeholder with a typical aspect ratio.

3. Avoid inserting content above existing content

Don't push existing content down. If you must inject a cookie banner or promo bar at the top of the viewport, either:

4. Stabilize web fonts

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: optional; /* or swap with size-adjust */
  size-adjust: 100%;
}

Or preload the font so it lands before FCP:

<link rel="preload" as="font" type="font/woff2" href="/fonts/inter.woff2" crossorigin />

5. Animate transform, not layout properties

/* WRONG: triggers layout */
.menu { left: 0; transition: left 0.3s; }

/* RIGHT: uses GPU compositing, no layout */
.menu { transform: translateX(0); transition: transform 0.3s; }

Verification

  1. Re-run Lighthouse, CLS should be < 0.1.
  2. Test on slow 3G in DevTools to catch font/image shifts that don't appear on fast networks.
  3. Check Chrome DevTools → Performance → Experience panel for individual shift events.

Related audits


Audit your URL at https://lighthouse-md.com.

Audit your page now

Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.

Run audit →