Web Vitals (CLS, LCP, FID)

Difficulty: Advanced

Question

What are Core Web Vitals? How does CSS affect them?

Answer

Core Web Vitals are Google's key metrics for user experience (affect SEO ranking):

1. LCP (Largest Contentful Paint): time for largest visible element to render. Target: < 2.5s 2. CLS (Cumulative Layout Shift): visual stability (elements jumping around). Target: < 0.1 3. INP (Interaction to Next Paint, replaced FID): responsiveness to user input. Target: < 200ms

CSS impact on Web Vitals: - LCP: render-blocking CSS, large images, custom fonts - CLS: images without dimensions, dynamically injected content, web fonts causing FOIT/FOUT - INP: long-running CSS animations, expensive selectors

Code examples

Preventing CLS (Layout Shifts)

/* 1. Always set image dimensions */
<img src="photo.jpg" width="800" height="600"
     alt="Photo" />
/* Or use aspect-ratio in CSS */
img {
  aspect-ratio: 4 / 3;
  width: 100%;
  height: auto;
}

/* 2. Reserve space for dynamic content */
.ad-slot {
  min-height: 250px; /* reserve space before ad loads */
}

/* 3. Prevent font swap layout shift */
@font-face {
  font-family: 'Inter';
  src: url('inter.woff2') format('woff2');
  font-display: swap;
  /* optional: prevents shift entirely but may flash */
  /* swap: shows fallback then swaps (may shift) */
}

/* 4. Avoid inserting content above existing content */
/* BAD: banner pushes everything down */
.notification-bar {
  /* If injected at top, shifts all content */
}
/* GOOD: use transform to slide in */
.notification-bar {
  transform: translateY(-100%);
  transition: transform 0.3s;
}
.notification-bar.visible {
  transform: translateY(0);
}

CLS is caused by elements that change size or position after initial render. Always reserve space for images, ads, and dynamic content.

Improving LCP

<!-- 1. Preload critical resources -->
<link rel="preload" as="image"
      href="hero-image.jpg" />
<link rel="preload" as="font"
      href="inter.woff2"
      type="font/woff2" crossorigin />

<!-- 2. Inline critical CSS -->
<style>
  /* Only above-the-fold styles */
  .hero { min-height: 100vh; }
  .nav { height: 64px; }
</style>
<link rel="stylesheet" href="full.css"
      media="print" onload="this.media='all'" />
<!-- Loads full CSS without blocking render -->

<!-- 3. Optimize LCP image -->
<img src="hero.jpg"
     srcset="hero-400.jpg 400w,
            hero-800.jpg 800w,
            hero-1200.jpg 1200w"
     sizes="100vw"
     loading="eager"
     fetchpriority="high"
     decoding="async"
     alt="Hero" />

<!-- 4. Avoid lazy loading above-the-fold images -->
<!-- loading="lazy" delays LCP for hero images -->

LCP measures when the largest visible element renders. Preload critical resources, inline critical CSS, and never lazy-load above-the-fold images.

CSS Performance Best Practices

/* 1. Minimize render-blocking CSS */
/* Split CSS: critical inline + rest async */

/* 2. Reduce unused CSS */
/* Use PurgeCSS or Tailwind's built-in purging */

/* 3. Avoid expensive selectors */
/* BAD */
*:not(.special) { } /* matches almost everything */
.wrapper > div > ul > li > a { } /* deep nesting */

/* GOOD */
.nav-link { } /* single class, fast */

/* 4. Use font-display */
@font-face {
  font-display: optional;
  /* optional: uses fallback if font takes too long */
  /* Best for CLS, may not show custom font */
}

/* 5. Use contain for component isolation */
.card {
  contain: content;
  /* Isolates layout/paint calculations */
}

/* 6. Use content-visibility for long pages */
.section {
  content-visibility: auto;
  contain-intrinsic-size: auto 500px;
  /* Browser skips rendering until scrolled into view */
}

content-visibility: auto can dramatically improve initial page load by skipping rendering of offscreen content. contain: content isolates recalculation scope.

Key points

Concepts covered

Core Web Vitals, CLS, LCP, FID, INP, Performance, SEO