# Cumulative layout shift (CLS) in Next.js

> How to fix cumulative layout shift (cls) in Next.js — with the exact fix and copy-paste code.

_Category: Performance · Detector `layout-thrashing` · Severity: warning_

Layout shift is when content jumps after it has already rendered — an image loads and pushes the text down, a banner injects itself above the fold, a web font swaps and reflows everything. It is a Core Web Vitals metric Google ranks on, and it makes users tap the wrong thing. AI-built pages shift constantly because generated markup omits `width`/`height` on images and drops late content in without reserving space.

## The fix for Next.js

`next/image` reserves space from the `width`/`height` (or fill + a sized parent) automatically, and `next/font` eliminates font-swap shift by self-hosting with a size-adjusted fallback. Using both removes the two most common CLS sources.

```tsx
import Image from 'next/image'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] }) // no layout shift on swap

<Image src="/hero.jpg" width={1200} height={630} alt="Hero" />
```

[Next.js docs](https://nextjs.org/docs/app/api-reference/components/image)

### Steps

1. Add `width` and `height` (or `aspect-ratio`) to every image, video, and iframe
2. Reserve a fixed-size slot for anything injected after load (ads, banners, embeds)
3. Use `font-display: optional` or a size-adjusted fallback to avoid font-swap reflow

## How VibeCheck detects it

The `layout-thrashing` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Layout shift cluster detected (3 shifts)`
- **Threshold:** ≥ 3 layout shifts within a 500ms window, with no recent user input

## FAQ

### What CLS score do I need?

Google considers CLS good at 0.1 or below, and poor above 0.25, for 75% of page loads. It is one of the three Core Web Vitals used in ranking.

### Why does the layout-thrashing detector flag this?

VibeCheck observes the browser’s layout-shift entries. When three or more fire within 500ms without user input, it flags a cluster — that burst is exactly what a jumpy load feels like.

### My image is responsive — do I still set `width` and `height`?

Yes. Set the intrinsic `width`/`height` attributes so the browser knows the aspect ratio, then use CSS (`width:100%`; `height:auto`) to scale it. That gives you responsiveness with zero shift.

See the general, framework-agnostic fix: https://vibecheck.wcgw.fun/fix/cumulative-layout-shift.md

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/cumulative-layout-shift. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
