Developer Tools

Web Performance Optimization: What Core Web Vitals Actually Measure and How to Fix Them

11 min readBy KBC Grandcentral Research Team

Google's 2021 page experience update made Core Web Vitals a ranking signal. Since then, LCP (Largest Contentful Paint), INP (Interaction to Next Paint), and CLS (Cumulative Layout Shift) have become the most-watched frontend metrics. But most optimization guides stop at 'compress your images.' The LCP on your product page is probably your hero image — but the reason it loads slowly might be your render-blocking CSS, not the image size.

Core Web Vitals: What They Measure and Google's ThresholdsLCPLargest Contentful PaintHow fast main content loads≤ 2.5s Good2.5–4s OK>4sFixes: image preload,remove render-blockingCSS/JS, CDN, WebPUsually: hero image or H1INPInteraction to Next PaintHow responsive UI feels≤200ms Good200–500ms>500Fixes: break up long tasks,yield to main thread,defer non-critical JSReplaced FID in Mar 2024CLSCumulative Layout ShiftHow stable layout is≤0.1 Good0.1–0.25 OK>0.25Fixes: set width/heighton images, avoid injectingcontent above existingAds, late-loading fonts75th Percentile of Your Visitors — Not Average

Key Takeaways

  • Core Web Vitals are measured at P75 — the 75th percentile of your actual visitors' experience, not an average or best-case
  • LCP is almost always an image — preload your LCP element with <link rel="preload" as="image"> and eliminate render-blocking resources
  • INP replaced FID in March 2024 — measures all interactions, not just the first; long JavaScript tasks are the primary cause of poor INP
  • CLS is caused by images without dimensions and late-loading content — always set width/height on images, reserve space for ads and embeds
  • Bundle splitting cuts initial JS payload — route-based code splitting ensures users only download code for the page they're on

LCP: Usually an Image, Sometimes a Heading

LCP identifies the largest element that's visible in the viewport when the page first loads — typically your hero image, product photo, or large H1 heading. The element itself is usually not the problem; the problem is what delays it from loading. Common culprits, in order of frequency:

LCP Delay CauseWhy It Delays LCPFix
Render-blocking CSSBrowser won't paint until CSS loadedMove critical CSS inline; defer non-critical
Render-blocking JSScripts with no async/defer block parseAdd defer/async to third-party scripts
LCP image not preloadedDiscovery delayed in HTML parse orderAdd rel=preload to the LCP image link tag
Image too large (file size)Download takes too longConvert to WebP/AVIF, compress, serve via CDN
Slow server response (TTFB)Everything waits for first byteCDN, server-side caching, edge functions
Client-side rendering (CSR) appsDOM built by JS, not HTMLSSR or SSG — serve pre-rendered HTML

INP: Breaking Up Long Tasks

INP measures the time from a user interaction (click, key press, tap) to when the browser renders the visual response. A long task on the main thread (any JavaScript execution over 50ms) blocks this response. The fix is yielding to the browser between work chunks using setTimeout(callback, 0), scheduler.yield() (Chrome 124+), or moving heavy computation to a Web Worker.

Breaking Up a Long Task to Improve INP:

// ❌ Blocks main thread — bad INP
function processItems(items) { items.forEach(item => heavyWork(item)) }
// ✅ Yields between chunks — good INP
async function processItemsYielding(items) {
for (let i = 0; i < items.length; i++) {
heavyWork(items[i])
if (i % 50 === 0) await new Promise(r => setTimeout(r, 0))
}
}

Image Optimization Tools

Image & Developer Tools

Image format converter (JPEG/WebP/PNG), color picker, SSL checker, and other web developer utilities to help improve your site's Core Web Vitals.

Open Developer Tools →