Resourcesโ€บWeb Performanceโ€บCore Web Vitals 2026: LCP, INP, CLS Explained and How to Fix Them
โšกWeb Performanceโ€” Core Web Vitals 2026: LCP, INP, CLS Explained and How to Fix Themโฑ 8 min

Core Web Vitals 2026: LCP, INP, CLS Explained and How to Fix Them

Google's Core Web Vitals are now a ranking factor. Here's what LCP, INP, and CLS measure and exactly how to improve each one.

๐Ÿ“…January 13, 2026โœTechTwitter.ioweb-performancecore-web-vitalsseolighthouse

What Are Core Web Vitals?

Core Web Vitals are Google's user-experience metrics that directly affect search ranking. In 2024, INP replaced FID as the third metric. The three metrics you need to care about:

MetricWhat It MeasuresGoodNeeds WorkPoor
LCPLargest Contentful Paint โ€” loading speed< 2.5s2.5sโ€“4s> 4s
INPInteraction to Next Paint โ€” responsiveness< 200ms200โ€“500ms> 500ms
CLSCumulative Layout Shift โ€” visual stability< 0.10.1โ€“0.25> 0.25

LCP: Largest Contentful Paint

LCP measures how long it takes for the largest visible element to render โ€” usually a hero image or main heading.

What causes bad LCP?

  • Slow server response time
  • Render-blocking CSS and JavaScript
  • Unoptimized hero images
  • Slow third-party resources

How to fix LCP

1. Preload the LCP image:

<link rel="preload" as="image" href="/hero.avif" fetchpriority="high" />

2. Use modern image formats:

<picture>
  <source srcset="/hero.avif" type="image/avif" />
  <source srcset="/hero.webp" type="image/webp" />
  <img src="/hero.jpg" alt="Hero" width="1200" height="600" />
</picture>

3. Remove render-blocking resources:

<!-- Defer non-critical JS -->
<script src="analytics.js" defer></script>

<!-- Load non-critical CSS asynchronously -->
<link rel="preload" href="non-critical.css" as="style" onload="this.rel='stylesheet'" />

4. Use a CDN โ€” server response time (TTFB) is often the biggest LCP factor. A CDN close to users can cut TTFB by 50-80%.


INP: Interaction to Next Paint

INP replaced FID in March 2024. It measures the worst-case interaction latency throughout the entire page visit โ€” not just the first interaction.

Every click, tap, and keypress is measured. INP is the 98th percentile of those measurements.

What causes bad INP?

  • Long-running JavaScript on the main thread
  • Heavy event handlers
  • Synchronous DOM manipulation after interaction
  • Large React re-renders triggered by clicks

How to fix INP

1. Break up long tasks:

// Bad: blocks the main thread for 500ms
function processData(items) {
  items.forEach(item => heavyOperation(item))
}

// Better: yield to browser between chunks
async function processData(items) {
  for (let i = 0; i < items.length; i++) {
    heavyOperation(items[i])
    if (i % 100 === 0) {
      await scheduler.yield() // yield to browser (Chrome 115+)
      // Fallback: await new Promise(r => setTimeout(r, 0))
    }
  }
}

2. Move work off the main thread:

// Web Workers for CPU-heavy tasks
const worker = new Worker('/heavy-worker.js')
worker.postMessage({ data: largeDataset })
worker.onmessage = (e) => updateUI(e.data)

3. Debounce expensive event handlers:

const handleSearch = debounce((value) => {
  fetchResults(value) // Only fire 300ms after user stops typing
}, 300)

CLS: Cumulative Layout Shift

CLS measures how much page content unexpectedly shifts during load. A score of 0 means nothing moved. Above 0.1 means users are clicking the wrong things.

What causes bad CLS?

  • Images without explicit width/height
  • Ads and embeds that load and push content down
  • Dynamic content injected above existing content
  • Web fonts causing text to reflow

How to fix CLS

1. Always set image dimensions:

<!-- Bad: browser doesn't know space to reserve -->
<img src="/product.jpg" alt="Product" />

<!-- Good: browser reserves exact space -->
<img src="/product.jpg" alt="Product" width="400" height="300" />

2. Reserve space for dynamic content:

/* Reserve space for ads before they load */
.ad-container {
  min-height: 250px;
  width: 300px;
}

3. Use font-display: optional or preload fonts:

@font-face {
  font-family: 'Inter';
  font-display: optional; /* Don't swap fonts after initial render */
}
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />

Measuring Core Web Vitals

In the browser (real data):

import { getLCP, getINP, getCLS } from 'web-vitals'

getLCP(console.log)
getINP(console.log)
getCLS(console.log)

Tools:

  • Chrome DevTools โ†’ Performance tab โ†’ Core Web Vitals
  • PageSpeed Insights โ€” real-world data from Chrome users
  • Lighthouse CI โ€” automate in your pipeline

Key Takeaways

  • LCP: preload your hero image, use AVIF/WebP, add a CDN
  • INP: break up long tasks, defer non-critical JS, debounce handlers
  • CLS: always set image dimensions, reserve space for dynamic content
  • Measure with real user data (PageSpeed Insights), not just lab tools (Lighthouse)
  • A CDN alone often fixes 60% of LCP issues โ€” it's the highest-leverage change