Code editor showing a critical CSS block inlined inside an HTML document headDetailed guide

Critical CSS Guide: Extract, Inline, and Defer Styles

View contents

Critical CSS Guide: Extract, Inline, and Defer Styles

Introduction

Critical CSS is the minimal subset of styles needed to render the visible above-the-fold content without waiting for the site's entire stylesheet to download. Chrome explicitly recommends "extract critical CSS" and "defer non-critical CSS" as part of its audit for minimizing main thread work. This guide covers how to implement it step by step. The UXR SEO Analyzer flags when it detects full stylesheets blocking rendering instead of inlined critical CSS.

Why Critical CSS Matters

By default, the browser can't build the render tree until it processes all the CSS it finds in the <head>—this is part of the critical rendering path. If your main stylesheet weighs 200 KB but only 8 KB corresponds to what the user sees before scrolling, the browser still waits for the full 200 KB before painting anything. Inlining just those 8 KB and deferring the rest removes that block.

This connects directly to the LCP technical breakdown: when the LCP element is a text block or depends on the initial layout, a high render delay is usually caused by blocking CSS, not a slow image. Reducing that phase is exactly what well-implemented critical CSS achieves.

Step 1: Identify the Critical CSS

Critical CSS covers the styles that affect elements visible in the initial viewport, at the screen sizes that matter to you (mobile and desktop, given your project's single breakpoint). Automated tools like critical, penthouse, or beasties (the maintained successor to Critters) render the page in a headless browser and extract the CSS rules that actually apply to that viewport.

// build-critical-css.js — example using the "critical" package
const critical = require('critical');

await critical.generate({
  inline: true,
  base: 'dist/',
  src: 'index.html',
  target: 'index.html',
  width: 1300,
  height: 900,
  dimensions: [
    { width: 375, height: 812 },  // mobile
    { width: 1300, height: 900 }, // desktop
  ],
});

Step 2: Inline the Critical CSS

The output gets injected directly into a <style> tag inside the <head>, avoiding an extra network request for the first paint:

<head>
  <style>
    /* Generated critical CSS, only ~8KB */
    body { margin: 0; font-family: system-ui, sans-serif; }
    .hero { min-height: 480px; background: #f5f5f5; }
    .hero h1 { font-size: 2.5rem; }
  </style>
</head>

Step 3: Defer the Non-Critical CSS

The rest of the stylesheet should load without blocking rendering. The standard pattern uses rel="preload" with a rel switch once it finishes loading, plus a <noscript> fallback:

<link rel="preload" href="/styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>

This pattern downloads main.css at low, non-blocking priority and activates it as a real stylesheet once downloaded, without delaying first paint.

Tooling by Stack

Stack Recommended approach
Static sites / SSG Extract critical CSS at build time with critical or beasties, per page
Vite / React / Vue Build plugin that runs extraction over the generated HTML before deploying
Next.js CSS-in-JS with automatic critical extraction, or an equivalent post-build step
WordPress and traditional CMS Performance plugins that generate critical CSS per template

Automating Extraction in Your Build Pipeline

Critical CSS goes stale every time you change the layout, so generating it by hand doesn't scale. The right approach is to make it a build step that runs on every deploy:

  1. The build generates the final HTML and CSS as usual
  2. A post-build script (using critical, beasties, or equivalent) opens each generated page in a headless browser
  3. The script extracts the CSS rules applied to the defined viewport and inlines them into each HTML file's <head>
  4. CI fails if the extraction step produces a block larger than the defined size budget (for example, 14KB)

For SSG sites with hundreds of pages, this step can be parallelized per page without significantly affecting build time, since each extraction is independent.

Critical CSS and Visual Stability (CLS)

One important side effect: if the critical CSS omits an above-the-fold element's dimensions (for example, an image container without aspect-ratio or min-height), the browser can paint that element with the wrong dimensions and then correct them once the full stylesheet arrives—producing exactly the kind of layout shift CLS penalizes. When building your critical CSS, verify it includes any rule that reserves space (dimensions, aspect-ratio, min-height) for elements visible above the fold, not just color and typography.

Common Mistakes

  • Extracting too much "critical" CSS—if the inlined block exceeds ~14KB, it starts competing with the HTML itself for the initial TCP packet and loses part of its advantage
  • Generating critical CSS for a single viewport only, ignoring the mobile layout most of your users will see
  • Forgetting to regenerate critical CSS after design changes, leaving stale styles inlined
  • Deferring styles that are actually critical, causing a visible flash of unstyled content (FOUC) once the full stylesheet applies

Critical CSS is just one of the resources that can block rendering. If Lighthouse still reports blocking resources after implementing it, the problem is likely synchronous scripts in the <head>—covered in Render-Blocking Resources Explained—or a slow TTFB delaying the HTML's arrival before any CSS, critical or not, can even apply.

Critical CSS Checklist

  • [ ] Critical CSS extracted per template or page type, not a single generic block
  • [ ] Inlined block under ~14KB compressed
  • [ ] Dimensions and aspect-ratio for above-the-fold elements included in the critical block
  • [ ] Full stylesheet loaded with rel="preload" + switch to stylesheet, with a <noscript> fallback
  • [ ] Extraction automated as a build step, not a manual process
  • [ ] Verified in Lighthouse that the full stylesheet no longer shows up as a blocking resource

How to Verify It

After implementing critical CSS, confirm in Chrome DevTools' Network panel that the main stylesheet downloads at low priority and no longer shows up in Lighthouse's "render-blocking resources" list. The UXR SEO Analyzer also flags this in its Performance tab.

Frequently Asked Questions

How much critical CSS is too much?

As a rule of thumb, keep the inlined block under 14KB compressed—the size of the initial TCP congestion window on most connections. More than that starts delaying the HTML instead of speeding it up.

Do I need different critical CSS per page?

On sites with very different templates (home, product, article), yes—each template has its own above-the-fold. On sites with a shared layout, a single critical block for the shell (header, navigation) is usually enough.

Does critical CSS replace minifying and compressing regular CSS?

No. They're complementary: minify and compress your entire stylesheet as a baseline practice, and additionally extract the critical subset for the first paint.

What if I use CSS-in-JS instead of separate stylesheets?

The principle is the same, but extraction changes: instead of parsing a .css file, the CSS-in-JS library needs native support for critical extraction on the server (rendering the page and collecting only the classes used). Several modern CSS-in-JS libraries include this capability; check your library's documentation before attempting to extract it manually.

References

  1. Chrome Developers - Minimize main thread work
  2. Chrome Developers - Eliminate render-blocking resources
  3. Chrome Developers - Avoid chaining critical requests
  4. web.dev - Core Web Vitals

Related articles

Category hub

Hub

Performance Technical Hub: Complete Web Optimization Guide

Curated index of our technical performance guides: critical CSS, JavaScript, server response, and blocking resources.

In the same category

Introduction

Render Blocking Resources Explained

Render-blocking resources are files that prevent the browser from displaying content to users until they are fully downloaded and processed

Other topics

Hub

Performance Seo Hub

Performance is a critical ranking factor and directly impacts user experience