Performance details
Did the paragraph jump when the hero loaded? That's CLS. It's preventable.
Image dimensions for CLS
Every <img> and <video> needs explicit width and height. Without them, the browser reserves zero space until the image loads, then content jumps.
Set intrinsic dimensions as HTML attributes:
Or use aspect-ratio in CSS:
Next.js <Image> requires width and height (or fill) and handles this automatically.
fetchpriority and loading
fetchpriority="high": use for the LCP element only. In Next.js: <Image priority />.
loading="lazy": defers until near viewport. Never on the LCP image.
Font loading: preload, preconnect, font-display
1. Preconnect to the font CDN
2. Preload critical fonts
crossorigin is required or the browser double-fetches. Preload only fonts used above the fold.
3. font-display: swap
Tune fallback metrics to reduce the visible shift:
Virtualization for large lists
Past ~50 items, render only rows in or near the viewport. 10,000 items, ~30 DOM nodes.
For lists that don't justify full virtualization, content-visibility: auto skips layout and paint for off-screen blocks:
Virtualization breaks Cmd/Ctrl+F, anchor links, and print views. Plan for these if they matter.
Common mistakes
- Removing width and height from images. Set intrinsic dimensions. Let CSS scale.
loading="lazy"on the LCP image. Delays the most important image.fetchpriority="high"on every image. Nothing is high priority if everything is.- No
font-displayin@font-face. Three seconds of invisible text. crossoriginmissing on font preload. Double-fetch.- Preloading every font weight. A megabyte before the page paints.
- Virtualizing a list of 20 items. Complexity for no benefit.