100/100 in Lighthouse ist ein Lab-Ergebnis. Die Core Web Vitals, die Google fürs Ranking nutzt, sind p75 im Chrome UX Report über 28 Tage. Wer beides vermischt, jagt einen Screenshot, während das Feld rot bleibt.
WordPress 7.1 auf PHP 8.4 kann grüne Vitals liefern. Es tut das nicht von allein. Ein Theme mit Page-Builder, ein Consent-Banner, das den Hero nach unten drückt, und ein Checkout-Widget, das beim Klick 200 KB hydriert, verlieren INP, bevor LCP überhaupt fertig ist. Diese Anleitung hat zwei Schichten: Feld (CrUX), das in Googles grünen Bändern liegen muss, und Lab (Lighthouse mobil), wo wir intern 100/100 jagen, weil das Disziplin bei Bildern, CSS und Drittanbietern erzwingt.
Googles veröffentlichtes „good“ für LCP ist 2,5 Sekunden auf p75 im Feld. Das hat sich in diesem Text nicht geändert, und wir tun nicht so, als hätte ein Dokument von 2026 die offizielle Liste auf 1,2 s gesenkt. Wenn wir sagen, der Hero sollte näher an einer Sekunde malen, ist das unser internes Lab-Budget, keine neue Google-Schwelle. INP „good“ ist 200 ms. CLS „good“ ist 0,1. Lab 100/100 will engere Zahlen, weil Lighthouse TTFB, ungenutztes CSS und Hauptthread-Arbeit in einem simulierten Lauf hart bestraft.
Auf deutschen Shops kommt dazu der Consent-Stack unter DSGVO und BFSG: Usercentrics und Cookiebot sind Alltag. Der Banner gehört in die Vitals-Rechnung, nicht in eine separate Compliance-Folie.
Feld gegen Lab: CrUX ist nicht Lighthouse
Lesen Sie zuerst die Feldkarte in PageSpeed Insights. Lab kommt danach als Diagnose, nicht als Urteil.
CrUX stammt von Chrome-Nutzern mit Telemetrie-Einwilligung. Das Fenster sind 28 Tage. Die Zahl, die zählt, ist das 75. Perzentil für URL oder Origin. Lighthouse ist Lab: ein Gerät, ein Netzwerkprofil, ein Load, oft ohne Login, ohne Zahlungs-Widget, ohne den Consent-Banner, der nur im EWR erscheint.
Was daraus folgt:
- Eine Seite kann LCP 1,1 s im Lab und 2,8 s im Feld haben, weil ein Teil der Treffer über 4G am Rand der Abdeckung kommt oder weil der Origin ohne HTML-Cache getroffen wird.
- Eine Seite kann 100 im Lab und rotes INP im Feld haben, weil Stripe, PayPal oder Klarna nur für Shop-Besucher injiziert werden.
- Eigenes RUM mit
web-vitals(onLCP,onINP,onCLS) persendBeaconliefert p75, bevor CrUX 28 Tage gerollt hat. Das steuert intern. Es ersetzt CrUX in der Search Console nicht.
Melden Sie niemals eine Lighthouse-Zahl so, als wäre sie CrUX. Der Screenshot aus dem Büro-WLAN ist kein Ranking-Signal.
| Messung | Quelle | Was sie ist | Was sie nicht ist |
|---|---|---|---|
| LCP p75 Feld | CrUX | Googles Ranking-Signal | Ein Lighthouse-Lauf |
| INP p75 Feld | CrUX | Alle Interaktionen, 200 ms grün | Erster Klick (das war FID) |
| CLS p75 Feld | CrUX | Unerwartete Layout-Verschiebung, 0,1 grün | „Auf dem Mac sah es stabil aus“ |
| 100/100 mobil | Lighthouse | Lab unter festem Profil | Feld, und keine Google-Schwelle |
LCP: Googles 2,5 s und unser Lab-Budget
Largest Contentful Paint ist die Zeit, bis das größte Inhaltselement im Viewport gemalt ist. Auf WordPress ist das fast immer das Hero-Bild, manchmal eine H1 über einem Hintergrundbild, das nie LCP wird, weil der Text gewinnt.
Google, Feld, p75: 2,5 s oder besser ist grün. Zwischen 2,5 und 4,0 s „needs improvement“. Über 4,0 s rot. Das ist die Liste. Intern jagen wir in Lighthouse mobil oft LCP unter 1,2 s, weil 100/100 das verlangt und weil es Puffer lässt, wenn das Feld härter ist als Lab. Das ist unser Ziel. Es ist keine neue Google-Schwelle.
LCP-Zeit ist TTFB plus Load-Delay plus Download plus Render-Delay. Typische WordPress-Fehler, in anderer Reihenfolge als die übliche Checkliste:
-
Origin ohne Cache. Preload hilft nicht, wenn HTML nach 700 ms ankommt. Anonymous-GET brauchen HTML-Cache vor dem Origin, mit Tag-Purge beim Publish, nicht „alles leeren“.
-
Hero mit
loading="lazy". Core und viele Themes lazy-laden alles. Lazy auf dem LCP-Bild verschiebt den Download-Start hinter das Layout. Lazy vom ersten Bild nehmen.fetchpriority="high"setzen. Preload im<head>mitimagesrcsetundimagesizes, die zum tatsächlich gezeigten Layout passen. -
AVIF statt schwerer Kampagnen-PNG. AVIF ist 2026 das Lieferformat. WebP ist Fallback. JPEG bleibt das Original in der Mediathek, nicht die Auslieferung. Ein Hero bei 1800 px braucht keinen 3-MB-Export aus dem letzten Briefing.
-
Schrift, die den Paint blockiert. Wenn LCP Text ist, liegt die Webfont auf dem kritischen Pfad. Subset auf die genutzten Skripte (für DE: latin und latin-ext),
font-display: optionaloder ein metric-angepasstes Fallback.
Zwei Fälle aus der Praxis:
- Ein WooCommerce-Katalog mit über 30 Plugins und TTFB um 1,8 s auf Kategorie-Templates. Related Products, Reviews, Schema und Mega-Menü wurden in PHP pro Request zusammengesetzt. HTML-Cache für anonyme Kategorie-URLs, AVIF-Heroes, kein Lazy auf dem ersten Bild. Feld-LCP bewegte sich. Checkout blieb uncached.
- Eine Page-Builder-Landing, die unter Kampagnenverkehr kollabierte. Der Builder malte jede Variante in PHP. Es gab keine Cache-Tag-Story, nur Purge-All. Wir haben die Seite nicht entkoppelt. Builder raus, gekoppeltes Theme, Redis und Page-Cache. Entkopplung eines Builder-Stacks ist ein redaktioneller Umbau, kein Hosting-Wechsel.
<?php
declare(strict_types=1);
add_action('wp_head', static function (): void {
if (!is_front_page() && !is_singular()) {
return;
}
$url = get_the_post_thumbnail_url(null, 'full');
if (!$url) {
return;
}
printf(
'<link rel="preload" as="image" href="%s" fetchpriority="high" />' . "\n",
esc_url($url)
);
}, 1);
Auf Astro 7 und Next.js 16 liegt Preload in der Vorlage, nicht in wp_head. Der Origin liefert URL und Maße über GraphQL. Das Frontend schreibt <link rel="preload"> und <img> mit width, height und AVIF-srcset. WordPress und Framework dürfen nicht parallel raten.
INP: 200 ms und Checkout-Widgets
Interaction to Next Paint hat FID 2024 abgelöst. FID maß den ersten Klick. INP misst Klick, Tap und Taste über die ganze Session. Grünes INP im Feld ist 200 ms oder besser auf p75. Zwischen 200 und 500 ms „needs improvement“. Über 500 ms rot. Lab 100/100 will oft deutlich unter 200 ms, weil Lighthouse lange Tasks hart bestraft.
INP ist Input-Delay plus Processing plus Presentation. Auf Shops ist Processing fast immer Drittanbieter, nicht Ihr toggleMenu().
Zahlungs- und Messaging-Widgets (Stripe, PayPal, Klarna On-site Messaging, Apple-Pay-Buttons) laden externes Skript, öffnen ein Modal und registrieren Handler auf Buttons in Hero oder Warenkorb. Liegt das Skript synchron im <head>, gehört der Hauptthread dem Widget, bevor der erste Menü-Klick kommt. Widget laden, wenn Checkout im Viewport ist (client:visible in Astro 7, dynamischer Import in Next.js 16), oder auf Idle. Der Button kann HTML mit href auf eine dünne Checkout-Route sein. Hydratisieren Sie das Widget dort, nicht auf der Startseite.
Weitere Punkte, die wir auf DE-Shops oft sehen:
- Google Tag Manager, Meta Pixel, Hotjar, Chat: Partytown oder Laden nach
requestIdleCallback. Nie auf dem kritischen Pfad. Partytown ist nicht gratis. Es verschiebt Arbeit in einen Worker. Es macht einen 400-KB-Tag-Container nicht klein. - Lange Listen (Shop-Filter, Mega-Menü):
scheduler.yield()zwischen Chunks, oder virtualisieren. EinquerySelectorAllüber 2000 Knoten im Click-Handler ist ein INP-Bruch. - Mobilmenü: der erste Tap auf den Hamburger ist oft die INP, die CrUX einfängt. Wartet der Klick auf die Hydration des ganzen Nav-Baums, sind 200 ms weg. Ein serverseitig gerendertes
<details>-Menü oder eine Insel nur für das Menü reicht. Hydratisieren Sie nicht den ganzen Header als eine React-Insel.
async function yieldToMain() {
if ('scheduler' in window && 'yield' in window.scheduler) {
return window.scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
Messen Sie INP im Feld pro Template, nicht als Origin-Durchschnitt. Ein Blog kann grün sein, während Checkout rot ist. Origin-CrUX versteckt das. URL-Ebene in der Search Console und eigenes RUM pro page_type zeigen es.
Cookie-Banner unter BFSG: die erste Interaktion darf nicht warten
Deutsche Shops und viele B2B-Seiten fahren Consent über Usercentrics, Cookiebot oder vergleichbare CMP. Parallel gilt das Barrierefreiheitsstärkungsgesetz (BFSG) als Umsetzung des European Accessibility Act: die Oberfläche muss bedienbar bleiben. Dieser Abschnitt bleibt bei den Vitals. Er ist kein Frist- oder Sanktions-Artikel zum Shop-Deadline-Thema.
Zwei Messgrößen kollidieren mit dem Banner:
- INP. Der erste sinnvolle Tap vieler Nutzer ist „Alle akzeptieren“, „Ablehnen“ oder „Einstellungen“. Wenn das CMP-Skript den Hauptthread hält, bis Tag Manager und 15 Vendoren initialisiert sind, liegt die Interaktion über 200 ms, bevor die UI reagiert. Felddaten auf DE-Shops zeigen das klarer als ein Lighthouse-Lauf ohne Banner.
- CLS. Wird der Banner nach dem ersten Paint eingehängt und schiebt Hero oder Navigation, summiert CrUX den Sprung. Lighthouse ohne EWR-Consent sieht ihn oft nicht.
Was wir in der Praxis verlangen, ohne Compliance-Theater:
- Die Consent-UI muss nach dem ersten HTML reagieren können. Skript verzögern (
defer, Idle, oder Insel nach Sichtbarkeit), aber den Wrapper und die fokussierbaren Controls nicht hinter einer langen Task-Queue verstecken. - Platz für den Banner in CSS reservieren (
min-heightauf einem Slot, der schon im ersten HTML liegt). Höhe nicht von 0 auf 96 px animieren. Overlay-Modale brauchen keinen Flow-Platz, dürfen aber nichtpadding-topauf<body>nach einer Messung umsetzen. - Usercentrics und Cookiebot nicht zusätzlich über GTM „noch einmal“ laden. Doppelte CMP ist doppelter Hauptthread und doppeltes CLS-Risiko.
- Accessibility-Anforderungen (Tastatur, Fokus, Kontrast) lösen Sie im Markup der CMP und Ihrer Theme-Schicht. Sie lösen sie nicht, indem Sie den Banner erst nach Hydration einblenden und den Hero verschieben.
Der Fehler, den wir am häufigsten sehen: Marketing fordert „Banner muss sofort und groß sichtbar sein“, Dev hängt das CMP synchron in <head>, Lighthouse im US-Profil bleibt grün, CrUX in DE wird rot. Feld zuerst messen, dann das CMP-Lademuster ändern. Mehr dazu im Core-Web-Vitals-Audit.
CLS: Layout-Sprünge jenseits des Banners
Cumulative Layout Shift summiert unerwartete Sprünge. Grünes CLS im Feld ist 0,1 oder besser. Lab 100/100 will nahe 0,00. Consent haben wir im BFSG-Abschnitt behandelt. Die übrigen Quellen:
Später Dark Mode. Wird die Theme-Klasse (dark auf <html> oder <body>) erst in einem Client-Skript nach dem ersten Paint gesetzt, springen Hintergrund, Text und Schatten. Das ist CLS und oft ein Flash. Fix: kleines synchrones <script> im <head> vor CSS, localStorage und matchMedia lesen, Farbvariablen so halten, dass der Wechsel die Geometrie nicht ändert. Farbe tauschen, nicht Schriftgröße und Zeilenhöhe. filter: invert auf body ist ein CLS- und Kontrastproblem, kein Theme.
Weitere CLS-Quellen:
- Bilder und Iframes:
width,heightoderaspect-ratio. YouTube-Embed in einer 16/9-Box. - Schriften:
size-adjust,ascent-overrideauf dem Fallback, damit Arial und Geist dieselbe Zeilenbox belegen. - Ads und Related-Blöcke:
min-height, nicht „wir wissen es erst, wenn die API antwortet“.
.consent-slot {
min-height: 96px;
}
.hero-media {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
@font-face {
font-family: Geist-Fallback;
src: local("Arial");
size-adjust: 106%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
Bilder und Schriften ohne LCP-Diebstahl
Die Mediathek speichert Originale. Die Auslieferung ist AVIF in 400, 768, 1200 und 1920 Breite, mit sizes, die zum Layout passen, nicht 100vw auf einem Artikel in einer 680-px-Spalte. loading="lazy" unterhalb der Falte. decoding="async". Kein Karussell im Hero, das fünf LCP-Kandidaten lädt.
Schriften: zwei Gewichte, nicht fünf. Subset. WOFF2. Self-Host, nicht eine Google-Fonts-CSS mit zwei Extra-Runden vor @font-face. Auf Astro 7 und Next.js 16 liegt das in der Build-Pipeline. Auf dem Monolith: Plugin oder Build, der Subset-Dateien schreibt, nicht Custom-Fonts als TTF aus dem Builder.
Kritisches CSS gehört ins erste Paket. Header, Typo und Hero-Box brauchen Style im HTML, unter etwa 14 KB komprimiert, damit der erste Paint nicht auf style.css wartet. Der Rest der Sheet lädt async. Builder-Themes, die 400 KB CSS an jede URL schicken, verlieren LCP, bevor das Bild erwähnt wird. Im Headless emittieren Astro und Next nur die Klassen, die die Seite nutzt. Im Monolith: Above-the-fold pro Template extrahieren oder Theme wechseln.
content-visibility: auto auf Kommentaren, Related-Grid und Footer senkt Style- und Layout-Arbeit beim ersten Paint. contain-intrinsic-size setzen, damit die Scrollbar nicht springt (das wäre CLS).
Kritische CSS und Preload-Hints gehören an die HTML-Grenze, nicht in ein weiteres mu-Plugin, das bei jedem PHP-Hit läuft. Ein CSS-Inliner-Plugin braucht trotzdem PHP-Start, Query und <style>-Druck. Das hilft dem Render-Delay nach TTFB. Es tut nichts für TTFB. Liegt der Origin bei 600 ms, ist das LCP-Budget schon weg, bevor der Inliner läuft.
Cloudflare HTMLRewriter (oder eine vergleichbare HTML-Transformation an der Edge) schreibt ein gecachtes Dokument um: Preload für das LCP-Bild injizieren, einen Tracker aus wp_footer streichen, fetchpriority nachziehen, wenn das Template es vergessen hat. Der PHP-Origin steckt in diesem Pfad nicht. Anonymous-GET bleibt ein Cache-Hit. Regeln, die wir nutzen: anonymes HTML mit Tags cachen (post-id, template-home, lang-de), Publish purgt Tags, nicht die Zone; HTMLRewriter nur sichere, idempotente Hints, keine Personalisierung; ein Inliner-Plugin höchstens während der Migration, dann raus. Zwei Inliner (Plugin plus Edge) verdoppeln Bytes und streiten ums <style>.
LiteSpeed Cache plus Cloudflare „cache everything“ plus Inliner sind drei Caches ohne gemeinsame Invalidierung. Der Redakteur speichert, der Origin aktualisiert, die Edge liefert zwei Stunden die gestrige Startseite. Das ist keine Core-Web-Vitals-Strategie. Das ist eine Support-Warteschlange.
Astro-6-Inseln und Next.js 16 für Vitals
Zwei Frontends, dieselbe Anforderung: erster Paint ohne unnötiges JavaScript.
Astro 7 ist der Default für Content. HTML und CSS raus. Inseln dort, wo es Klick gibt. client:idle für Suche. client:visible für Warenkorb-Widget. Ein Artikel ohne Inseln sendet 0 KB JS und gewinnt Lab. Deshalb ist 100/100 auf einem Magazin erreichbar, ohne das Design zu betrügen.
Next.js 16 passt, wenn die Seite eine App ist. PPR: statische Shell, dynamische Löcher. React Server Components für die Liste, Client-Component für den Filter. Der ganze App Router als "use client" am Layout verschenkt INP. Partial Prerendering hilft LCP. Es hilft nicht, wenn useEffect im Root-Layout Tag Manager und Zahlungs-Widget gleichzeitig lädt.
Ein Monolith auf PHP 8.4 mit engem Theme, Redis und Cloudflare kann im Feld ebenfalls grün werden. Er verliert, wenn die Redaktion „noch ein kleines“ Popup-Plugin installiert. Headless verliert, wenn die Insel das ganze Icon-Pack importiert. Architektur wählen Sie im Headless-Leitfaden. Vitals sind das Ergebnis dieser Architektur plus Drittanbieter.
Speculation Rules (<script type="speculationrules"> mit konservativem Prerender auf internen Links) drücken die nächste Navigation in unterstützten Chrome-Clients Richtung null. Das verbessert empfundene Geschwindigkeit. Es ändert nicht LCP auf einem Landing von Google, und genau diese URL interessiert CrUX.
PHP 8.4, Redis und TTFB hinter Cloudflare
Uncached HTML auf Shared Hosting ist die LCP-Decke. Redis Object Cache senkt SQL für eingeloggte Nutzer und Cache-Misses. Opcache auf 8.4 senkt den PHP-Start. Ein Page-Cache davor (Cloudflare, oder Nginx fastcgi_cache auf eigener VPS) nimmt PHP für anonyme Treffer ganz aus dem Weg.
Priorität:
- HTML-Cache für Anonyme, mit Purge beim Publish.
- Redis für
WP_Queryund Transients. - Weniger Plugins im Front. Jedes
wp_enqueue_scriptist INP. - Datenbank-Indexes und Autoload-Aufräumen. Autoload von 2 MB in
wp_optionsist TTFB, bevor das Theme startet.
WordPress 7.1 ändert daran nichts. Core ist nicht das LCP-Problem. Die Script-Queue und die Distanz zum Origin sind es.
RUM, Budgets und Regression
Lab in CI: Lighthouse-Budgets auf PRs für die Templates, die zählen (Home, Artikel, Produkt, Checkout). Build failen, wenn JS auf dem Artikel-Template ein paar Dutzend Kilobyte überschreitet oder dem LCP-Element Maße fehlen. Das fängt Regression durch ein neues Plugin oder eine neue Insel.
Feld: web-vitals an Ihren Endpoint, aggregiertes p75 pro Template pro Woche. Alarm, wenn INP im Feld 200 ms überschreitet, nicht wenn jemand Lighthouse im Büro-WLAN gefahren hat. CrUX API wöchentlich als Referenz gegen die Search Console.
Budgets, die eine Kampagnenwoche überleben:
- Consent-Wrapper hat Höhe in CSS.
- Theme-Skript im
<head>unter 1 KB, ohne Layout anzufassen. - Zahlungs-Widgets nicht auf der Startseite.
- Hero ist AVIF, preload, nicht lazy.
- CMP (Usercentrics/Cookiebot) nicht doppelt über GTM.
Ohne Budget ist 100/100 ein Screenshot aus der Launch-Woche.
Multisite ändert die Schwellen nicht. Es ändert die Origin-Last. Eine Redis-Instanz pro Netzwerk, HTML-Cache pro Blog-ID, und kein gemeinsames all.min.js, das WooCommerce-Skripte auf dem Magazin-Site lädt. Damit kann Multisite in CrUX so grün liegen wie eine Einzelinstallation. Ohne das erbt jede Site die langsame Enqueue der Nachbarin.
Audit und weiterführende Lektüre
Der Core-Web-Vitals-Audit ist Feld plus Lab plus eine Liste von Drittanbietern, die vom Hauptthread müssen. Wir öffnen zuerst CrUX und Search Console, danach Lighthouse, und wir messen Checkout als eigenes Template.
Geschwindigkeitsarbeit am bestehenden Monolith steht in Wie man eine WordPress-basierte Website beschleunigt. Entkopplung als Topologie, nicht als Performance-Zauber, im Headless-Architektur-Leitfaden.
Fazit
Google hat die LCP-Liste nicht auf 1,2 s gesenkt. Grünes LCP im Feld bleibt 2,5 s. Grünes INP ist 200 ms. Grünes CLS ist 0,1. 100/100 ist Lab-Disziplin. Auf WordPress heißt das: HTML-Cache vor dem Origin, Platz und Idle-Load für den Cookie-Banner unter BFSG, Theme ohne FOUC, Checkout-Widgets weg von der ersten Interaktion, Edge-Rewrite für Hints statt eines weiteren PHP-Inliners. Das trennt grünes Feld von einem hübschen Lighthouse-Screenshot.
Schreiben Sie mit URL und Search-Console-Zugang, wenn das Feld rot ist und das Lab lügt. Der kommerzielle Einstieg ist der Core-Web-Vitals-Audit.





