Skip to content
kobiakov.dev
Zurück zum Blog

Web-Performance 2026: LCP, CLS, INP, Schriften und Cloudinary

Ein praktischer Leitfaden zu grünen Core Web Vitals 2026 — echte Messwerte, Cloudinary-Bildoptimierung, Schrift-Ladestrategie und die neue INP-Metrik.

Vladyslav Kobiakov4 Min. Lesezeit
Web-Performance 2026: LCP, CLS, INP, Schriften und Cloudinary

Googles Core Web Vitals waren in dem Moment kein abstraktes SEO-Thema mehr, in dem sie zum Ranking-Signal wurden. 2026 ist das Bestehen der drei Schwellenwerte — LCP unter 2,5 s, CLS unter 0,1, INP unter 200 ms — die Grundvoraussetzung für jede Seite, die in der organischen Suche mithalten will. In diesem Beitrag geht es darum, was diese Zahlen auf einer Next.js-Seite tatsächlich bewegt.

Die Metrik-Landschaft 2026

Google hat FID (First Input Delay) im März 2024 offiziell abgelöst und durch INP (Interaction to Next Paint) ersetzt. INP misst die Latenz der langsamsten Interaktion während eines Seitenbesuchs — nicht nur der ersten. Das ist wichtig, weil FID sich leicht austricksen ließ, indem man JavaScript aufschob; INP erfasst langsame Klick-Handler an jeder Stelle der Sitzung.

Aktuelle Schwellenwerte:

| Metrik | Gut | Verbesserungswürdig | Schlecht | |---|---|---|---| | LCP | ≤ 2,5 s | 2,5 s – 4,0 s | > 4,0 s | | CLS | ≤ 0,1 | 0,1 – 0,25 | > 0,25 | | INP | ≤ 200 ms | 200 ms – 500 ms | > 500 ms |

LCP: Fast immer ist das Bild der Übeltäter

Largest Contentful Paint ist typischerweise das Hero-Bild oder die <h1>. Auf einer Portfolio-Seite ist es fast immer das Hero-Bild.

Priority-Hint + Preload

Sagen Sie dem Browser sofort, dass das Hero-Bild kritisch ist:

// HeroSection.tsx import Image from 'next/image'; export function HeroSection() { return ( <Image src="/hero.webp" alt="Hero" width={1200} height={630} priority // deaktiviert Lazy-Loading, setzt fetchpriority="high" quality={85} /> ); }
tsx

next/image mit priority erzeugt automatisch ein <link rel="preload"> im <head>. Der Browser lädt das Bild parallel zum HTML-Parsing.

Cloudinary für responsive Bilder

Ein 1200-px-Bild an einen 390-px-Mobilbildschirm auszuliefern verschwendet ~60 % Bandbreite. Die URL-API von Cloudinary übernimmt die responsive Skalierung, ohne mehrere Varianten zu speichern:

// lib/cloudinary.ts export function cloudinaryUrl( publicId: string, options: { width: number; quality?: number; format?: string } = { width: 800 } ) { const { width, quality = 'auto', format = 'auto' } = options; return `https://res.cloudinary.com/${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/image/upload/w_${width},q_${quality},f_${format}/${publicId}`; }
ts

Kombiniert mit der sizes-Prop von next/image:

<Image src={cloudinaryUrl('projects/hero', { width: 1200 })} sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" fill alt="Projekt-Hero" priority />
tsx

Der Browser wählt die passende Größe je nach Viewport. Ein 390-px-Bildschirm lädt ein ~390-px-Bild, kein 1200-px-Bild.

LCP-Debugging

Nutzen Sie das Performance-Panel der Chrome DevTools mit „LCP candidate"-Markern oder Lighthouse in der Node-CI:

npx lighthouse https://kobiakov.dev --output json | \ jq '.audits["largest-contentful-paint"].displayValue'
bash

Eine gute Regel: Wenn das LCP-Element ein Bild ist, sollte seine URL im <head> als Preload oder im initialen HTML stehen (nicht per JavaScript eingefügt).

CLS: Layout-Shift kommt aus drei Quellen

Cumulative Layout Shift misst unerwartete Bewegungen von Seitenelementen. In der Praxis stammen 90 % des CLS aus:

  1. Bildern ohne explizite Abmessungen — der Browser weiß nicht, wie viel Platz er reservieren soll
  2. Spät ladenden Web-Schriften — Text springt um, wenn die eigene Schrift einspringt
  3. Dynamischem Inhalt über bestehendem Inhalt — Cookie-Banner, spät ladende Anzeigen

Bilder

Setzen Sie immer width und height auf <Image>. Für responsive Bilder mit fill umschließen Sie sie mit einem Container mit explizitem Seitenverhältnis:

<div className="relative aspect-video"> <Image src={src} alt={alt} fill className="object-cover" /> </div>
tsx

aspect-video (16:9) reserviert genau den richtigen Platz. Kein Shift, wenn das Bild lädt.

Schriften

Die schlechteste Schrift-Ladestrategie ist die Standardeinstellung: kein font-display, kein Preload, Schriften von einem Drittanbieter-CDN.

// app/layout.tsx — next/font (Zero-CLS-Ansatz) import { Inter, JetBrains_Mono } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], display: 'swap', // sofort Fallback zeigen, bei Bereitschaft tauschen variable: '--font-inter', preload: true, });
ts

next/font lädt Schriften zur Build-Zeit herunter und hostet sie selbst von Ihrer Domain. Kein Cross-Origin-Request, kein CLS durch späten Schrift-Tausch. display: 'swap' plus das size-adjust-CSS (automatisch von next/font ergänzt) passt die Fallback-Schrift an die Metriken der eigenen Schrift an — der visuelle Versatz ist nicht wahrnehmbar.

INP: Der neue Ersatz für FID

INP > 200 ms bedeutet meist eines von:

  • Ein Klick-Handler, der synchrone Arbeit im Main-Thread erledigt
  • Eine React-Komponente, die bei Interaktion zu viel neu rendert
  • Drittanbieter-Skripte, die den Main-Thread blockieren

Long Tasks identifizieren

Suchen Sie im Performance-Panel der Chrome DevTools nach Tasks länger als 50 ms (rot markiert). Filtern Sie im Activity-Tab nach „Long tasks".

Schwere Arbeit mit dem Scheduler aufteilen

Wenn Sie bei einer Nutzerinteraktion CPU-intensive Arbeit erledigen müssen, geben Sie zwischen den Blöcken die Kontrolle an den Browser zurück:

async function processLargeList(items: Item[]) { const CHUNK_SIZE = 50; for (let i = 0; i < items.length; i += CHUNK_SIZE) { const chunk = items.slice(i, i + CHUNK_SIZE); processChunk(chunk); // An den Browser zurückgeben: erlaubt Paint + Eingabeverarbeitung await new Promise(resolve => scheduler.postTask(resolve, { priority: 'background' })); } }
ts

React-Re-Renders reduzieren

INP-Spitzen bei Filter-/Such-Interaktionen lassen sich oft auf eine Komponente zurückführen, die ihre ganze Liste neu rendert. useMemo für abgeleitete Daten, React.memo für Listenelemente:

const filteredProjects = useMemo( () => projects.filter(p => p.tags.includes(activeTag)), [projects, activeTag] );
ts

Messen in der CI

Verlassen Sie sich nicht auf lokale Lighthouse-Läufe. Die Performance echter Nutzer schwankt. Ergänzen Sie automatisierte Messungen in Ihrer CI-Pipeline:

# .github/workflows/perf.yml - name: Lighthouse CI uses: treosh/lighthouse-ci-action@v12 with: urls: | https://staging.kobiakov.dev/ https://staging.kobiakov.dev/blog budgetPath: ./lighthouse-budget.json uploadArtifacts: true
yaml
// lighthouse-budget.json [{ "path": "/*", "timings": [ { "metric": "largest-contentful-paint", "budget": 2500 }, { "metric": "interactive", "budget": 3500 } ], "resourceSizes": [ { "resourceType": "script", "budget": 300 }, { "resourceType": "image", "budget": 500 } ] }]
json

Ein verfehltes Budget bricht den CI-Build, bevor die Performance-Regression die Produktion erreicht.

Quick Wins auf einen Blick

| Änderung | Wirkung | |---|---| | priority zum Hero-Bild hinzufügen | LCP -0,5 bis -1,5 s | | Auf next/font umstellen | CLS -0,05 bis -0,15 | | Explizite Abmessungen für alle Bilder | CLS nahe null | | Cloudinary f_auto,q_auto | LCP -0,2 bis -0,8 s auf Mobil | | Nicht-kritisches JS aufschieben (next/script strategy="lazyOnload") | INP -20 bis -80 ms |

Jede dieser Maßnahmen ist in unter 30 Minuten umgesetzt. Zusammen heben sie einen Lighthouse-Score von 60–70 typischerweise auf 95+.

Share: