Web Vitals — what actually matters (LCP, INP, CLS) and how to optimize each
LCP measures loading (largest paint), INP measures interaction responsiveness (replaced FID in 2024), CLS measures layout stability. Optimize each with different levers: LCP via image/critical-resource pipeline, INP via task scheduling, CLS via reserving space.
Three Core Web Vitals as of 2024+:
LCP — Largest Contentful Paint (≤ 2.5s for "good"). Time to paint the largest above-the-fold element (often the hero image or H1). Levers:
- Compress + size the LCP image (AVIF/WebP, srcset, fetchpriority="high").
- Eliminate render-blocking CSS/JS; inline critical CSS for above-the-fold.
- Use a CDN; static-render the page if possible.
- Preconnect to the origin serving the LCP element.
INP — Interaction to Next Paint (≤ 200ms). Replaced FID in March 2024. Worst-case latency between any user input and the next paint. Levers:
- Break long tasks (>50ms) with
yieldToMain/scheduler.postTask. - Move CPU work off the main thread with Web Workers.
- Defer non-critical work (analytics, ads) until after interaction.
- Avoid layout thrash inside event handlers (read-then-write batched).
CLS — Cumulative Layout Shift (≤ 0.1). Sum of unexpected layout shifts during the page lifetime. Levers:
- Always set
width/heighton images and<video>(lets the browser reserve space). - Reserve space for ads/embeds.
- Avoid inserting content above existing content (especially banners).
- Use
font-display: optionalorsize-adjustto avoid text reflow on font load.
Measure with the web-vitals library (real users) and Lighthouse / PageSpeed Insights (lab). Real-user numbers from CrUX are what Google ranks on.
Code
Follow-up questions
- •Why was FID replaced by INP?
- •How do you investigate a 'long task' shown in DevTools?
- •How does third-party JS typically degrade CLS and INP?
Common mistakes
- •Optimizing the wrong vital — improving LCP when INP is the user complaint.
- •Trusting Lighthouse alone; field data (CrUX) is what Google ranks on.
- •Lazy-loading the LCP image — adds a round trip and tanks LCP.
Performance considerations
- •Server-side render the LCP element as plain HTML — avoid hydration on the critical path.
- •Defer hydration of below-the-fold islands (Astro, RSC, partial hydration).
Edge cases
- •Single-page apps need to instrument soft navigations explicitly — built-in vitals only cover the initial nav.
- •INP samples the *worst* interaction; one bad click ruins the page's score.
Real-world examples
- •Vercel/Next dashboards expose INP regression alerts on PRs — caught before users complain.