Zurück zum Blog
8 Min. LesezeitPerformance

Web Performance in 2025: Core Web Vitals and Beyond

Master modern web performance optimization with Core Web Vitals, resource loading strategies, and cutting-edge techniques for lightning-fast websites.

Web Performance in 2025: Core Web Vitals and Beyond

Web performance isn't just about fast load times—it's about creating smooth, responsive experiences that keep users engaged. With Core Web Vitals becoming a ranking factor, performance optimization is more important than ever.

Core Web Vitals

Google's Core Web Vitals measure user-centric performance:

1. Largest Contentful Paint (LCP)

Measures loading performance. Target: < 2.5 seconds

// Measure LCP
new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });

Optimization strategies:

<!-- Preload critical images -->
<link rel="preload" as="image" href="/hero.jpg">

<!-- Optimize image formats -->
<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img src="/hero.jpg" alt="Hero" loading="eager">
</picture>

<!-- Inline critical CSS -->
<style>
  /* Critical above-the-fold styles */
</style>

2. First Input Delay (FID) / Interaction to Next Paint (INP)

Measures responsiveness. Target: < 100ms (FID), < 200ms (INP)

// Measure FID
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('FID:', entry.processingStart - entry.startTime);
  }
}).observe({ type: 'first-input', buffered: true });

Optimization strategies:

// Break up long tasks
async function processItems(items) {
  for (const item of items) {
    await processItem(item);

    // Yield to browser
    if (performance.now() % 50 < 16) {
      await new Promise(resolve => setTimeout(resolve, 0));
    }
  }
}

// Use requestIdleCallback
requestIdleCallback(() => {
  // Non-critical work
  analyticstracking();
}, { timeout: 2000 });

// Defer non-critical JavaScript
<script defer src="/analytics.js"></script>

3. Cumulative Layout Shift (CLS)

Measures visual stability. Target: < 0.1

// Measure CLS
let clsScore = 0;

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      clsScore += entry.value;
    }
  }
  console.log('CLS:', clsScore);
}).observe({ type: 'layout-shift', buffered: true });

Optimization strategies:

/* Reserve space for images */
img {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
}

/* Reserve space for ads */
.ad-slot {
  min-height: 250px;
}

/* Avoid inserting content above existing content */
.notification {
  position: fixed; /* Don't shift content */
  top: 0;
}

Resource Loading Strategies

1. Critical Resource Hints

<!-- DNS prefetch for external domains -->
<link rel="dns-prefetch" href="https://api.example.com">

<!-- Preconnect to establish early connections -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- Prefetch resources for next page -->
<link rel="prefetch" href="/next-page.html">

<!-- Preload critical resources -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>

2. JavaScript Loading

<!-- Defer non-critical scripts -->
<script defer src="/app.js"></script>

<!-- Async for independent scripts -->
<script async src="/analytics.js"></script>

<!-- Module preload -->
<link rel="modulepreload" href="/app.js">

3. Dynamic Imports

// Lazy load features
button.addEventListener('click', async () => {
  const { heavyFeature } = await import('./heavy-feature.js');
  heavyFeature();
});

// Route-based code splitting
const routes = {
  '/products': () => import('./pages/products.js'),
  '/cart': () => import('./pages/cart.js'),
};

Image Optimization

1. Modern Formats

<picture>
  <!-- AVIF: Best compression -->
  <source srcset="/image.avif" type="image/avif">

  <!-- WebP: Good compression, wide support -->
  <source srcset="/image.webp" type="image/webp">

  <!-- JPEG: Fallback -->
  <img src="/image.jpg" alt="Description" loading="lazy">
</picture>

2. Responsive Images

<img
  src="/image-800.jpg"
  srcset="
    /image-400.jpg 400w,
    /image-800.jpg 800w,
    /image-1200.jpg 1200w
  "
  sizes="(max-width: 600px) 400px, 800px"
  alt="Description"
  loading="lazy"
  decoding="async"
>

3. Lazy Loading

// Native lazy loading
<img src="/image.jpg" loading="lazy">

// Intersection Observer for custom loading
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach(img => {
  observer.observe(img);
});

4. Image CDNs

<!-- Cloudinary -->
<img src="https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/sample.jpg">

<!-- Imgix -->
<img src="https://assets.imgix.net/image.jpg?w=800&auto=format,compress">

<!-- Cloudflare Images -->
<img src="https://imagedelivery.net/account/image/w=800,f=auto">

Font Optimization

1. Modern Loading Strategy

@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/font.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap; /* Show fallback immediately */
}

2. Variable Fonts

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900; /* Support all weights */
  font-display: swap;
}

h1 {
  font-family: 'Inter', sans-serif;
  font-weight: 700; /* Any weight from 100-900 */
}

3. Subsetting

# Create subset with only needed characters
pyftsubset font.ttf \
  --unicodes="U+0020-007E" \
  --output-file="font-subset.woff2" \
  --flavor=woff2

4. Preload Critical Fonts

<link
  rel="preload"
  href="/fonts/font.woff2"
  as="font"
  type="font/woff2"
  crossorigin
>

Bundle Optimization

1. Code Splitting

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
        },
        common: {
          minChunks: 2,
          name: 'common',
        },
      },
    },
  },
};

2. Tree Shaking

// package.json
{
  "sideEffects": false
}

// Use named imports
import { specific } from 'library'; // ✓ Tree-shakeable
import library from 'library'; // ✗ Imports everything

3. Bundle Analysis

# webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer

# Add to webpack config
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

plugins: [
  new BundleAnalyzerPlugin()
]

Caching Strategies

1. HTTP Caching

# nginx configuration
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

location ~* \.(html)$ {
  expires 1h;
  add_header Cache-Control "public, must-revalidate";
}

2. Cache Busting

// Webpack
output: {
  filename: '[name].[contenthash].js',
}

// Vite
build: {
  rollupOptions: {
    output: {
      entryFileNames: '[name].[hash].js',
    },
  },
}

3. Service Worker Caching

// Workbox strategies
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';

// Cache images
registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new CacheableResponsePlugin({ statuses: [0, 200] }),
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60,
      }),
    ],
  })
);

Rendering Strategies

1. Static Site Generation (SSG)

// Next.js
export async function getStaticProps() {
  const data = await fetchData();
  return { props: { data } };
}

Best for: Blogs, marketing sites, documentation

2. Incremental Static Regeneration (ISR)

export async function getStaticProps() {
  return {
    props: { data },
    revalidate: 60, // Rebuild every 60 seconds
  };
}

Best for: E-commerce, news sites with frequent updates

3. Server-Side Rendering (SSR)

export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { data } };
}

Best for: Personalized content, real-time data

4. Client-Side Rendering (CSR)

useEffect(() => {
  fetchData().then(setData);
}, []);

Best for: Authenticated pages, dashboards

Performance Monitoring

1. Real User Monitoring (RUM)

// web-vitals library
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

function sendToAnalytics(metric) {
  fetch('/analytics', {
    method: 'POST',
    body: JSON.stringify(metric),
  });
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);

2. Performance API

// Measure custom timings
performance.mark('feature-start');
// ... feature code ...
performance.mark('feature-end');
performance.measure('feature', 'feature-start', 'feature-end');

const measure = performance.getEntriesByName('feature')[0];
console.log('Feature took:', measure.duration, 'ms');

3. Network Information API

if ('connection' in navigator) {
  const connection = navigator.connection;

  if (connection.effectiveType === '4g') {
    // Load high-quality assets
  } else {
    // Load lower-quality assets
  }

  connection.addEventListener('change', () => {
    console.log('Connection changed:', connection.effectiveType);
  });
}

Advanced Techniques

1. Priority Hints

<!-- High priority for critical resources -->
<img src="/hero.jpg" fetchpriority="high">

<!-- Low priority for below-the-fold images -->
<img src="/footer.jpg" fetchpriority="low">

<!-- Normal priority (default) -->
<img src="/content.jpg" fetchpriority="auto">

2. Compression

# nginx gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1000;

# Brotli (better compression)
brotli on;
brotli_types text/plain text/css application/json application/javascript;

3. HTTP/2 Server Push

# Push critical resources
location / {
  http2_push /style.css;
  http2_push /script.js;
}

4. Early Hints (103 Status)

// Express.js
app.get('/', (req, res) => {
  // Send early hints
  res.writeEarlyHints({
    link: [
      '<style.css>; rel=preload; as=style',
      '<script.js>; rel=preload; as=script',
    ],
  });

  // Send actual response
  res.send(html);
});

Performance Budget

Set and enforce performance budgets:

// webpack.config.js
module.exports = {
  performance: {
    maxEntrypointSize: 250000, // 250kb
    maxAssetSize: 100000, // 100kb
    hints: 'error',
  },
};
// Lighthouse CI budget
[
  {
    "resourceSizes": [
      { "resourceType": "script", "budget": 125 },
      { "resourceType": "image", "budget": 200 },
      { "resourceType": "total", "budget": 500 }
    ],
    "timings": [
      { "metric": "interactive", "budget": 3000 },
      { "metric": "first-contentful-paint", "budget": 1500 }
    ]
  }
]

Testing Tools

1. Lighthouse

lighthouse https://example.com --output=html --output-path=./report.html

2. WebPageTest

  • Visit webpagetest.org
  • Test from multiple locations
  • View filmstrip and waterfall

3. Chrome DevTools

  • Performance tab for profiling
  • Coverage tab for unused code
  • Network tab for resource analysis
  • Lighthouse tab for audits

Checklist

Images:

  • Modern formats (AVIF, WebP)
  • Responsive images
  • Lazy loading
  • Proper sizing

JavaScript:

  • Code splitting
  • Defer/async loading
  • Tree shaking
  • Minification

CSS:

  • Critical CSS inline
  • Non-critical CSS deferred
  • Unused CSS removed
  • Minification

Fonts:

  • WOFF2 format
  • font-display: swap
  • Subsetting
  • Preload critical fonts

Caching:

  • Long cache times for static assets
  • Cache busting
  • Service worker caching

Monitoring:

  • Real user monitoring
  • Core Web Vitals tracking
  • Performance budget

Conclusion

Web performance is a continuous journey, not a destination. By focusing on Core Web Vitals, optimizing resources, and monitoring real user experiences, you can build websites that are fast, responsive, and delightful to use.

Start with the basics—optimize images, defer JavaScript, inline critical CSS—then progressively enhance with advanced techniques.

Your users (and search rankings) will thank you.

👨‍💻

Jordan Patel

Webentwickler & Technologie-Enthusiast