Cumulative layout shift (CLS) in Next.js
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.
Symptoms
How VibeCheck catches it
In your widget · Problems
To your coding agent · MCP
The same string in your widget and in your agent’s context — no screenshot, no copy-paste.
Root causes
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.
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" />Steps
- Add
widthandheight(oraspect-ratio) to every image, video, and iframe - Reserve a fixed-size slot for anything injected after load (ads, banners, embeds)
- Use
font-display: optionalor a size-adjusted fallback to avoid font-swap reflow
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
widthandheight? - Yes. Set the intrinsic
width/heightattributes so the browser knows the aspect ratio, then use CSS (width:100%;height:auto) to scale it. That gives you responsiveness with zero shift.