Image layout shift is one of those bugs that makes a page feel cheap.
The content loads, the image arrives late, the text jumps, and the user loses their place.
In Next.js, the fix is not complicated: give the browser stable dimensions and use a placeholder only as polish, not as a layout crutch.
The Rule
No known image box -> layout shift risk
Known width/height -> stable layout
Blur placeholder -> nicer loading
Local Image Example
import Image from "next/image";
import hero from "@/public/hero.jpg";
export default function Hero() {
return (
<Image
src={hero}
alt="Dashboard showing image performance metrics"
priority
placeholder="blur"
sizes="100vw"
className="heroImage"
/>
);
}
For static imports, Next.js can infer dimensions and generate blur data.
That is the easiest path.
Remote Image Example
Remote images need explicit dimensions:
<Image
src="https://example.com/product.jpg"
alt="Product preview"
width={1200}
height={800}
placeholder="blur"
blurDataURL={blurDataUrl}
sizes="(max-width: 768px) 100vw, 720px"
/>
If you do not know the dimensions, fetch or store them before render. Guessing is how CLS sneaks back in.
CSS Must Not Break the Ratio
.heroImage {
width: 100%;
height: auto;
object-fit: cover;
border-radius: 12px;
}
Avoid setting random height without thinking about aspect ratio.
Production Checklist
| Check | Why |
|---|---|
width and height set |
prevents layout shift |
meaningful alt
|
accessibility |
sizes accurate |
avoids oversized downloads |
priority only for hero |
avoids stealing bandwidth |
| blur placeholder small | avoids bloated HTML |
| remote domains configured | avoids runtime failures |
My Take on LQIP
LQIP is not the main performance feature. It is a perceived performance feature.
The real layout fix is reserving the image box.
Blur-up makes the wait feel smoother, but it will not save a layout that does not know its own dimensions.
Final Thought
Zero CLS images are mostly discipline: dimensions, ratios, correct sizes, and not treating placeholders as magic.
What image bug has caused the most layout pain in your Next.js projects?
Top comments (0)