performanceFeatured

Core Web Vitals optimieren: LCP, FID, CLS unter Kontrolle

Praktischer Guide zur Optimierung von Core Web Vitals: Largest Contentful Paint, First Input Delay und Cumulative Layout Shift für besseres Ranking.

Onur Cirakoglu
10 min read
#Core Web Vitals#Performance#SEO#LCP#FID#CLS
Web Performance Metriken Dashboard mit Core Web Vitals

Core Web Vitals sind seit 2021 offizieller Google Ranking-Faktor. Websites mit schlechten Werten verlieren Rankings, Traffic und Conversions. In diesem Guide zeigen wir, wie Sie LCP, FID und CLS systematisch optimieren.

Was sind Core Web Vitals?

Google definiert drei zentrale Metriken für User Experience:

1. Largest Contentful Paint (LCP)

Was: Zeit bis größtes Element im Viewport sichtbar ist

Ziel: < 2.5 Sekunden

Häufige LCP-Elemente:

  • Hero Images
  • Header-Bilder
  • Text-Blocks
  • Video-Thumbnails

2. First Input Delay (FID)

Was: Zeit zwischen erstem User-Input und Browser-Response

Ziel: < 100 Millisekunden

Typische Inputs:

  • Button-Clicks
  • Link-Clicks
  • Input-Felder

NEU: Ab 2024 wird FID durch INP (Interaction to Next Paint) ersetzt!

3. Cumulative Layout Shift (CLS)

Was: Summe aller unerwarteten Layout-Verschiebungen

Ziel: < 0.1

Häufige Ursachen:

  • Bilder ohne Dimensions
  • Fonts ohne fallback
  • Dynamisch injizierte Ads
  • Late-loading Content

LCP optimieren: 8 bewährte Techniken

1. Images mit next/image optimieren

// ❌ Schlecht: Unoptimiertes Bild
<img src="/hero.jpg" alt="Hero" />
 
// ✅ Optimal: next/image mit Priority
import Image from 'next/image'
 
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1920}
  height={1080}
  priority  // ⭐ Kritisch für LCP!
  sizes="100vw"
  quality={85}
/>

Impact: LCP von 3.2s → 0.8s (-75%)

2. Preload kritische Ressourcen

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        {/* Preload Hero Image */}
        <link
          rel="preload"
          as="image"
          href="/hero.jpg"
          imageSrcSet="/hero-640.jpg 640w, /hero-1200.jpg 1200w"
        />
 
        {/* Preload kritische Fonts */}
        <link
          rel="preload"
          href="/fonts/inter.woff2"
          as="font"
          type="font/woff2"
          crossOrigin="anonymous"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}

3. Server-Side Rendering nutzen

// ✅ Server Component lädt Daten bevor HTML generiert wird
export default async function ProductPage({ params }) {
  // Daten bereits im initial HTML enthalten
  const product = await db.product.findUnique({
    where: { id: params.id }
  })
 
  return (
    <div>
      <h1>{product.title}</h1>
      <Image src={product.image} width={800} height={600} priority />
    </div>
  )
}

Mehr zu SSR vs CSR.

4. CDN für statische Assets

// next.config.js
module.exports = {
  images: {
    domains: ['cdn.headon.pro'],
    loader: 'custom',
    loaderFile: './imageLoader.js',
  },
}
// imageLoader.js
export default function cloudinaryLoader({ src, width, quality }) {
  return `https://cdn.headon.pro/image/upload/w_${width},q_${quality || 75}/${src}`
}

5. Critical CSS inlinen

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        {/* Inline Critical CSS */}
        <style dangerouslySetInnerHTML={{
          __html: `
            .hero { min-height: 100vh; background: linear-gradient(...); }
            .nav { position: sticky; top: 0; }
          `
        }} />
      </head>
      <body>{children}</body>
    </html>
  )
}

6. Lazy Load Below-the-Fold Content

export default function Page() {
  return (
    <div>
      {/* Above the fold - sofort laden */}
      <Hero />
 
      {/* Below the fold - lazy */}
      <Suspense fallback={<Skeleton />}>
        <BelowFoldContent />
      </Suspense>
    </div>
  )
}

7. Fonts optimieren

// app/layout.tsx
import { Inter } from 'next/font/google'
 
const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // ⭐ Verhindert FOIT
  preload: true,
  variable: '--font-inter',
})
 
export default function RootLayout({ children }) {
  return (
    <html className={inter.variable}>
      <body>{children}</body>
    </html>
  )
}

8. Render-Blocking Resources minimieren

import Script from 'next/script'
 
export default function Page() {
  return (
    <>
      {/* ❌ Blocking: Synchrones Script */}
      {/* <script src="analytics.js"></script> */}
 
      {/* ✅ Non-blocking */}
      <Script
        src="https://analytics.example.com/script.js"
        strategy="afterInteractive"
      />
    </>
  )
}

FID/INP optimieren: Interaktivität verbessern

1. JavaScript-Execution optimieren

// ❌ Schlecht: Blocking JavaScript
function handleClick() {
  const result = heavyComputation() // Blockiert 500ms!
  setData(result)
}
 
// ✅ Gut: Mit Web Worker
const worker = new Worker('/worker.js')
 
function handleClick() {
  worker.postMessage({ action: 'compute' })
  worker.onmessage = (e) => {
    setData(e.data) // Main Thread bleibt frei
  }
}

2. Code-Splitting aggressive nutzen

import dynamic from 'next/dynamic'
 
// ✅ Heavy Components lazy laden
const HeavyChart = dynamic(() => import('./HeavyChart'), {
  ssr: false,
  loading: () => <Skeleton />
})
 
const ComplexForm = dynamic(() => import('./ComplexForm'))
 
export default function Dashboard() {
  const [showChart, setShowChart] = useState(false)
 
  return (
    <div>
      <button onClick={() => setShowChart(true)}>
        Show Chart
      </button>
 
      {showChart && <HeavyChart />}
    </div>
  )
}

3. Event-Listener optimieren

'use client'
 
import { useMemo, useCallback } from 'react'
import debounce from 'lodash/debounce'
 
export default function SearchInput() {
  // ✅ Debounced Handler
  const handleSearch = useCallback(
    debounce((query: string) => {
      performSearch(query)
    }, 300),
    []
  )
 
  // ✅ Memoized Results
  const results = useMemo(() => {
    return expensiveFilter(data, query)
  }, [data, query])
 
  return (
    <input
      type="text"
      onChange={(e) => handleSearch(e.target.value)}
    />
  )
}

4. Long Tasks aufbrechen

// ❌ Schlecht: Lange Aufgabe blockiert Thread
function processLargeDataset(data) {
  for (let i = 0; i < data.length; i++) {
    processItem(data[i]) // 10.000+ Items!
  }
}
 
// ✅ Gut: Mit requestIdleCallback
function processLargeDataset(data) {
  let index = 0
 
  function processBatch() {
    const deadline = Date.now() + 50 // Max 50ms pro Batch
 
    while (index < data.length && Date.now() < deadline) {
      processItem(data[index])
      index++
    }
 
    if (index < data.length) {
      requestIdleCallback(processBatch)
    }
  }
 
  requestIdleCallback(processBatch)
}

5. Third-Party Scripts verzögern

export default function Page() {
  return (
    <>
      {/* ✅ Analytics erst nach Interaktion */}
      <Script
        src="https://www.googletagmanager.com/gtag/js"
        strategy="lazyOnload"
      />
 
      {/* ✅ Chat Widget erst nach Idle */}
      <Script
        src="https://widget.intercom.io/widget.js"
        strategy="worker" // Läuft in Partytown Worker
      />
    </>
  )
}

CLS eliminieren: Stabile Layouts

1. Image & Video Dimensions setzen

// ❌ CLS verursacht!
<img src="/product.jpg" alt="Product" />
 
// ✅ Aspect Ratio reserviert
<Image
  src="/product.jpg"
  alt="Product"
  width={800}
  height={600} // Verhindert Shift!
  sizes="(max-width: 768px) 100vw, 50vw"
/>

2. Font Loading optimieren

/* ✅ Font-Display Swap verhindert FOIT/FOUT */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* ⭐ Kritisch für CLS */
  font-weight: 400;
}
 
/* ✅ Fallback Font Size Match */
body {
  font-family: 'CustomFont', Arial, sans-serif;
  /* Adjust fallback size to match */
  font-size-adjust: 0.5;
}

3. Skeleton Screens verwenden

export default function Page() {
  return (
    <div>
      <Suspense fallback={
        <div className="h-96 bg-gray-200 animate-pulse" />
      }>
        <HeroImage />
      </Suspense>
 
      <Suspense fallback={
        <div className="space-y-4">
          <div className="h-8 bg-gray-200 rounded" />
          <div className="h-4 bg-gray-200 rounded w-3/4" />
        </div>
      }>
        <Content />
      </Suspense>
    </div>
  )
}

4. Ad-Slots reservieren

export default function Article() {
  return (
    <article>
      <h1>Article Title</h1>
 
      {/* ✅ Reserved space verhindert Shift */}
      <div className="min-h-[250px] bg-gray-100">
        <AdBanner slot="article-top" />
      </div>
 
      <div>Article content...</div>
 
      <div className="min-h-[250px] bg-gray-100">
        <AdBanner slot="article-bottom" />
      </div>
    </article>
  )
}

5. CSS Containment nutzen

/* ✅ Layout Isolation */
.card {
  contain: layout style paint;
}
 
.sidebar {
  contain: size layout;
}
 
/* ✅ Content Visibility für Off-screen */
.below-fold {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

Core Web Vitals Monitoring

1. Real User Monitoring (RUM)

// app/layout.tsx
'use client'
 
import { useReportWebVitals } from 'next/web-vitals'
 
export function WebVitals() {
  useReportWebVitals((metric) => {
    // An Analytics senden
    window.gtag('event', metric.name, {
      value: Math.round(metric.value),
      event_label: metric.id,
      non_interaction: true,
    })
 
    // Oder an eigenes Backend
    fetch('/api/analytics', {
      method: 'POST',
      body: JSON.stringify(metric),
    })
  })
 
  return null
}

2. Chrome User Experience Report (CrUX)

# CrUX API Query
curl "https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://headon.pro",
    "formFactor": "PHONE",
    "metrics": ["largest_contentful_paint", "cumulative_layout_shift"]
  }'

3. Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [pull_request]
 
jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Lighthouse CI
        run: |
          npm install -g @lhci/cli
          lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      startServerCommand: 'npm run start',
      url: ['http://localhost:3000/', 'http://localhost:3000/blog'],
    },
    assert: {
      assertions: {
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'first-input-delay': ['error', { maxNumericValue: 100 }],
      },
    },
  },
}

Best Practices Checklist

LCP Checklist

  • [ ] Hero Image mit priority Flag
  • [ ] Critical resources preloaded
  • [ ] Server-Side Rendering aktiviert
  • [ ] CDN für Images konfiguriert
  • [ ] Critical CSS inlined
  • [ ] Font-Display: swap gesetzt
  • [ ] Lazy Loading für below-fold

FID/INP Checklist

  • [ ] Keine Long Tasks (>50ms)
  • [ ] Heavy JavaScript lazy geladen
  • [ ] Event Listeners debounced
  • [ ] Web Workers für CPU-intensive Tasks
  • [ ] Third-party Scripts verzögert

CLS Checklist

  • [ ] Alle Images haben width/height
  • [ ] Font-Display Swap aktiviert
  • [ ] Skeleton Screens implementiert
  • [ ] Ad Slots reserviert
  • [ ] CSS Containment genutzt
  • [ ] Content Visibility für Off-screen

Tools für Core Web Vitals

Testing:

Monitoring:

Real-World Verbesserungen

Bei unseren Projekten konnten wir folgende Verbesserungen erzielen:

E-Commerce Site:

  • LCP: 3.8s → 1.1s (-71%)
  • FID: 180ms → 45ms (-75%)
  • CLS: 0.28 → 0.05 (-82%)
  • Resultat: +18% Conversion Rate

Blog:

  • LCP: 2.9s → 0.7s (-76%)
  • FID: 95ms → 32ms (-66%)
  • CLS: 0.15 → 0.03 (-80%)
  • Resultat: Google Ranking Seite 3 → Seite 1

Zusammenfassung

Core Web Vitals optimieren ist systematisch:

LCP < 2.5s durch Image-Optimization und SSR ✅ FID/INP < 100ms durch Code-Splitting und Web Workers ✅ CLS < 0.1 durch Dimensions und Skeleton Screens

Monitoring ist kritisch - messen Sie kontinuierlich!

Brauchen Sie Performance-Support?

Als Performance-Experten bieten wir:

  • 🔍 Detailliertes Performance-Audit
  • 🎯 Core Web Vitals Optimierung
  • 📊 Monitoring-Setup (RUM + Synthetic)
  • 🚀 Implementation aller Optimierungen

Performance-Audit anfragen

Weitere Guides

Aktualisiert: Juli 2024

#Core Web Vitals#Performance#SEO#LCP#FID#CLS