Minifying JavaScript promises speed and delivers 3% of LCP at best. Serving the right image delivers 30%. That scale gap drives this breakdown of Core Web Vitals: the metrics Google feeds into ranking, with optimizations ranked by measured production impact rather than checklist order.

What thresholds define a passing score?

LCP under 2.5s measures loading perception of the largest visible element. INP, which replaced FID in March 2024, demands responses to interactions within 200ms across the whole session. CLS stays under 0.1 when nothing jumps on screen. Field data beats lab numbers: CrUX and RUM capture mid-range Androids on 4G, while your MacBook with an SSD tells another story.

Why do images dominate LCP?

The hero tends to be an image, so that is where the gain lives. AVIF or WebP cuts 20 to 50% of weight against JPEG, srcset serves the right size per viewport, and fetchpriority="high" moves the main element forward in the download queue. The classic mistake persists: applying loading="lazy" to the LCP element itself makes the browser discover the image after layout, and you pay seconds of delay.

What blocks INP?

  • Long tasks on the main thread: route-level code splitting and deferred hydration give the browser room to respond
  • Third-party scripts: tag managers, chat widgets, and ad pixels cost hundreds of ms per interaction
  • Oversized DOM trees: past about 1,400 nodes, style recalcs and layout slow down

scheduler.yield() breaks up long tasks without surrendering priority, and the effect shows up in INP.

Where does CLS come from?

Images missing width and height, web font swaps, and banners injected above content explain most cases. For fonts, font-display: optional beats swap on CLS because it removes the visible fallback period. Reserve space with aspect-ratio and preload fonts used above the fold.

How much JavaScript does your page need?

Ship less code: route-level code splitting is default in Next.js and Nuxt, yet monolithic bundles still show up in legacy SPAs. Run a bundle analyzer (webpack-bundle-analyzer, rollup-plugin-visualizer) and verify tree-shaking does its job. Dependency audits retired moment.js from plenty of projects; every removed freeloader beats any runtime microbenchmark.

What role does the server play?

Edge caching with correct Cache-Control headers takes the origin out of the equation for repeat visits. Early Hints (status 103) preloads critical CSS before the server finishes building the HTML. The SSR versus CSR call deserves a per-route decision, not a per-app one: marketing pages render on the server, authenticated dashboards fetch client-side from cache.

How do you measure without fooling yourself?

The Core Web Vitals report in Search Console flags which templates suffer in the field. PageSpeed Insights diagnoses URL by URL, and the web-vitals library ships real metrics to your analytics with attribution to releases. Set alerts for field metric regressions within a week of each deploy; the culprit stays fresh in the git log.