Skip to content
Performance

Critical CSS Extraction

Extract and inline critical CSS to eliminate render-blocking stylesheets and speed up first paint.

stellae.design

6 min read

Introduction

CSS is render-blocking by default — the browser won't paint anything until all CSS is downloaded and parsed. Critical CSS extraction identifies styles needed for the initial viewport, inlines them, and defers the rest.

This technique can improve First Contentful Paint by 1-3 seconds on slower connections, making it one of the highest-impact CSS optimizations.

This guide covers automated extraction tools and implementation patterns for modern frameworks.


Key Concepts

The Inline + Defer Pattern

html
<head>
  <style>/* Only above-the-fold styles */
    body { margin: 0; font-family: system-ui; }
    .header { display: flex; padding: 1rem; }
    .hero { min-height: 60vh; display: grid; place-items: center; }
  </style>
  <link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>

Practical Examples

1. Critters Plugin

javascript
// webpack
const Critters = require('critters-webpack-plugin');
module.exports = { plugins: [new Critters({ preload: 'swap', inlineFonts: false })] };

// Vite
import critters from 'vite-plugin-critters';
export default defineConfig({ plugins: [critters()] });

2. PurgeCSS

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('@fullhuman/postcss-purgecss')({
      content: ['./src/**/*.{html,tsx,jsx}'],
      safelist: ['active', 'open', /^data-/],
    }),
  ],
};

3. Next.js Automatic CSS Optimization

javascript
module.exports = { experimental: { optimizeCss: true } };

Best Practices

  • ✅ Automate critical CSS extraction in your build pipeline
  • ✅ Keep critical CSS under 14KB (fits in first TCP round-trip)
  • ✅ Use CSS Modules or CSS-in-JS for per-component splitting
  • ✅ Run PurgeCSS to remove unused styles
  • ❌ Don't manually maintain critical CSS — it will drift
  • ❌ Don't inline your entire stylesheet

Common Pitfalls

  • 🚫 Inlining too much CSS — exceeding 14KB can slow initial load
  • 🚫 Breaking interactive states like :hover and :focus
  • 🚫 Not testing on real pages — different pages need different critical CSS
  • 🚫 Forgetting the noscript fallback

Performanceperformance

Was this article helpful?