Seitenbefund
  • Sample report
  • How it works
  • Blog
  • FAQ
  • For agencies
  • Pricing
EN/DEStart free website check
EN/DE
← Back to all posts
Performance·April 18, 2026·4 min read

Core Web Vitals explained

What LCP, INP and CLS measure, why a Lighthouse 100 can still ship a slow site, and which fixes move most audits.

by Lukas Freitag

Core Web Vitals are field metrics. Google aggregates them from real Chrome users via the Chrome User Experience Report; they are not the numbers your local Lighthouse run produces. Conflating the two is the single most common mistake we see in audits — teams optimize for the lab, the field stays bad, the rankings drift down, and nobody can explain why.

LCP: the largest paint in the initial viewport

Largest Contentful Paint records when the largest image or text element in the initial viewport renders. The "good" threshold is 2.5 seconds at the 75th percentile of real users.

The patterns that drive bad LCP, in order of frequency:

  • A hero image with no fetchpriority="high". The browser walks the preload queue: CSS, fonts, sometimes a Google Tag Manager script, and only then the JPEG. On a mid-range Android over LTE that ordering alone costs 800 ms.
  • An LCP element that does not exist in the initial HTML. Client-only React apps that render the hero after hydration regularly post LCP at 4 s+. Server rendering or static HTML fixes this without any JavaScript optimization.
  • Missing srcset. A 2400 px hero shipped to a 390 px iPhone takes longer to decode than to download.

The single highest-leverage change: identify the LCP element in DevTools (Performance panel, the LCP marker), mark it with fetchpriority="high", and ship a srcset that covers at least mobile, tablet, and desktop widths.

INP: every interaction, not just the first

Interaction to Next Paint replaced First Input Delay in March 2024. The substantive change: FID measured only the first interaction's input delay. INP measures the worst interaction across the whole session, end-to-end (input delay plus processing plus presentation). "Good" is 200 ms at p75.

  • #core-web-vitals
  • #lcp
  • #inp
  • #cls
  • #performance

German version: core-web-vitals-erklaert

Want to see where your site stands?

The free short check inspects visibility, structure, performance, and the technical baseline of your domain — passively, in minutes.

Start the short check

Related posts

  • SEO·April 29, 2026·3 min read

    Schema.org for small businesses

    Most small business sites need only three schema types. Here is what helps rich results and what we remove during audits.

    Read more →
  • Legal·April 25, 2026·3 min read

    Cookie banners without dark patterns

    Three consent rules most banners break, the CJEU equivalence requirement, and a minimal pattern that avoids dark patterns.

    Read more →
← Back to all posts
Seitenbefund

Passive website inspection for visibility, structure, performance, accessibility and baseline technical security.

Services

  • Penetration testing
  • SEO remediation
  • Accessibility remediation
  • Baseline security hardening

Legal

  • Imprint
  • Privacy
  • Terms

© 2026 Seitenbefund kontakt@seitenbefund.de

We only fetch publicly reachable pages. No logins, no port scans, no active security testing.

The dominant cause of bad INP scores is long tasks on the main thread. A click handler that synchronously filters and transforms a 5,000-row list will block the main thread for 250 ms or more. The fix is to break the work up.

// Bad: blocks the main thread for the full filter+map
function onClick() {
  const result = items.filter((i) => heavyCheck(i)).map(transform)
  setState(result)
}

// Better: yield to the scheduler so the browser can paint
function onClick() {
  scheduler.postTask(
    () => {
      const result = items.filter((i) => heavyCheck(i)).map(transform)
      setState(result)
    },
    { priority: 'user-blocking' },
  )
}

scheduler.postTask has been stable since Chrome 94 and is the clean way to break work into yieldable chunks. For older browsers, a setTimeout(fn, 0) is the historical workaround — it works, it just doesn't communicate priority to the browser.

CLS: the layout that jumps

Cumulative Layout Shift is the sum of all unexpected layout shifts after the first render. The threshold is 0.1.

Three sources dominate every audit:

  1. Images without explicit dimensions. <img> tags missing width and height attributes (or a CSS aspect-ratio). The reflow when the image arrives shifts everything below it.
  2. Web fonts swapping in. font-display: swap shifts every text block when the web font loads. font-display: optional gives the browser permission to skip the swap if the font wasn't already cached, which is usually what you want for body copy.
  3. Cookie banners and ad slots inserted late. The pattern is always the same: the team reserves no vertical space, the banner pops in 800 ms after first paint, every header below jumps by 80 px. CLS over 0.3 is routine.

The fix for category 1 is trivial and lands a CLS under 0.1 in nearly every audit we run: write width and height on every <img> tag, and let CSS scale with height: auto.

What the Vitals don't catch

Vitals say nothing about the cost of a bundle on a slow connection, nothing about memory pressure, nothing about the third-party scripts your tag manager might be loading. A site with perfect Vitals can be unusable on a Pixel 4a over 3G if it ships 2 MB of JavaScript. The Vitals are a floor, not a proof of quality.

The leverage point

If you fix LCP, INP and CLS often follow. A hero with fetchpriority="high" and explicit dimensions shifts the render profile so far forward that the rest of the JavaScript has time to parse before the user clicks anything. One change, three metrics move.

To see what your domain ships today, run the Seitenbefund short check — passive measurement, no installation, results in minutes.