A Core Web Vitals Budget You Can Actually Ship
Concrete numbers, the handful of techniques that move them, and how to stop a fast site from slowly getting slow.

Performance work fails for a boring reason: nobody wrote down the number. "Make it fast" is not a budget. These are, and they are the ones I put in writing before a project starts.
| Metric | Budget | Fails when |
|---|---|---|
| LCP | < 2.5s | Hero image is lazy, or fonts block paint |
| CLS | < 0.1 | Images without dimensions; late-loading banners |
| INP | < 200ms | Hydrating components nobody interacts with |
| JS shipped | < 120kB gzip | A client component in the layout |
LCP is almost always one image
On a content site the largest contentful paint is the hero. Three things fix it and they are not negotiable: mark it priority so it is preloaded rather than lazy, give it explicit dimensions, and serve AVIF.
<Image
src={cover.src}
alt={cover.alt}
width={cover.width}
height={cover.height}
placeholder="blur"
blurDataURL={cover.blurDataURL}
priority
sizes="100vw"
/>Everything below the fold gets the opposite treatment: lazy by default, with a blur placeholder so the space is reserved and the page never jumps.
CLS is a discipline, not a fix
Layout shift comes from four places, and all four are preventable:
- Images without dimensions. Project width and height from the CMS and pass them through.
- Fonts. Self-host with
next/font, usedisplay: swap, and let it generate the metric-matched fallback. - Late content. Anything that appears after hydration must occupy its space beforehand.
- Animation. Animate
transformandopacityonly. Animating height or margin is a shift with extra steps.
INP is a JavaScript problem
Interaction latency on a content site is nearly always self-inflicted: a client component high in the tree that hydrates the entire page. The fix is architectural rather than clever.
Keep layouts and pages as server components. Push "use client" down to the smallest leaf that genuinely needs state — a menu toggle, a scroll reveal, a counter. Everything else stays HTML.

Stopping the slow slide
Fast sites get slow one reasonable-sounding addition at a time. Two habits keep it honest: run Lighthouse on the same three URLs — home, an article, a case study — every time, and treat a regression as a bug with an owner, not a note in a backlog.
The motion layer is usually the first thing to blame and rarely the actual culprit. Scroll reveals gated behind prefers-reduced-motion and restricted to transform and opacity cost almost nothing; a marketing script costs everything.
// tagged


