TL;DR: CSS blockiert standardmäßig das Rendering. Critical CSS-Inlining extrahiert Above-the-Fold-Stile in den
<head>, lädt das vollständige CSS asynchron und eliminiert renderblockierende Anfragen. Dieser Leitfaden behandelt Extraktionswerkzeuge, Inlining-Schwellenwerte und asynchrone Lademuster. Angewendet auf tanstackship.com.
Einführung
Jede externe CSS-Datei verursacht einen Roundtrip, der das Seiten-Rendering blockiert. Das Inlining von Critical CSS – den Stilen, die für den anfänglichen Viewport-Inhalt benötigt werden – eliminiert diese Roundtrips für den First Paint und verbessert den Largest Contentful Paint drastisch.
Wie Critical CSS funktioniert
| Ansatz | First Paint | Implementierungsaufwand | Wartung |
|---|---|---|---|
Volles CSS im <head> | Sofort | Keiner (alles inlined) | CSS kann nicht gecacht werden |
| Extrahiertes Critical CSS | Fast sofort | Mittel | Erfordert Build-Schritt |
| HTTP/2 Server Push | Schnell | Gering | In Chrome veraltet |
| Inline + asynchrones volles CSS | Fast sofort | Mittel | Beste Balance |
| Critical CSS + Preload | Sofort | Hoch | Optimales Produktions-Setup |
Extraktion von Critical CSS
// Extraktion zur Build-Zeit mit dem critical-Paket
import { generate } from 'critical'
await generate({
base: 'dist/',
src: 'index.html',
target: 'index.html',
inline: true,
width: 1440,
height: 900,
extract: true,
})
Dies generiert eine index.html, bei der kritische Stile inlined sind und das vollständige CSS asynchron geladen wird.
Asynchrones CSS-Lademuster
<!-- Kritisches CSS inlined im <head> -->
<style>
/* ~15KB Above-the-Fold-Stile */
header, nav, .hero { ... }
</style>
<!-- Vollständiges CSS wird asynchron geladen -->
<link rel="preload" href="/assets/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/styles.css"></noscript>
Umsetzung in der Produktion
// TanStack Start: Critical CSS Middleware
import { defineMiddleware } from '~/lib/middleware'
export const criticalCSSMiddleware = defineMiddleware({
async after({ response }) {
if (response.headers.get('Content-Type')?.includes('text/html')) {
const html = await response.text()
const criticalCSS = extractCriticalCSS(html)
const optimized = html.replace(
'</head>',
`<style id="critical-css">${criticalCSS}</style>
<link rel="preload" href="/assets/styles.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/styles.css"></noscript>
</head>`
)
return new Response(optimized, response)
}
}
})
Richtlinien für Inlining-Schwellenwerte
| Szenario | Max. Inline-CSS-Größe | Auswirkung |
|---|---|---|
| Mobilgerät (3G) | 10-15 KB | Spart 300-800ms |
| Desktop (WLAN) | 20-30 KB | Spart 100-300ms |
| Erster Besuch | Kleiner ist besser | Größter Gewinn |
| Wiederkehrender Besuch | Dem Cache überlassen | Geringere Auswirkung |
Fazit
Das Inlining von Critical CSS gehört zu den Leistungsoptimierungen mit dem höchsten ROI. Extrahieren Sie Above-the-Fold-Stile zur Build-Zeit, setzen Sie sie als Inline-CSS in den <head> ein und laden Sie das vollständige Stylesheet asynchron. Dies eliminiert renderblockierende CSS-Anfragen und liefert einen beinahe sofortigen First Paint.
Für ergänzende Performance-Muster sehen Sie sich unsere Lade-Strategien für Schriftarten in Web-Apps und den Preload, Prefetch und Preconnect Leitfaden an – zusammen decken sie den gesamten kritischen Rendering-Pfad ab. Kombinieren Sie dies mit der Reduzierung der Time to First Byte (TTFB) und dem Leitfaden zur Optimierung der Core Web Vitals für eine umfassende Performance-Strategie.