Critical CSS: Delivering Only What the Browser Needs First
Your website’s CSS file might be 200KB. But when a visitor lands on your homepage, the browser only needs a fraction of that to render what’s visible on screen. The rest (styles for the footer, the contact page, the blog archive) can wait.
This is the core idea behind critical CSS: identify the styles needed to render the above-the-fold content, inline them directly in the HTML, and defer everything else. It sounds simple. The impact on performance is anything but. Anyone starting from scratch will get more out of our long form guide to website performance.
We’ve seen this single optimization cut perceived load times in half for client websites. Pages that used to show a blank white screen for two seconds suddenly render meaningful content in under a second. And in a world where Google’s Core Web Vitals directly influence your search rankings, that kind of improvement matters.
Let’s dig into how critical CSS works, how to implement it, and the tools that make it practical for real-world projects.
Why CSS Blocks Rendering (and Why That’s a Problem)
To understand why critical CSS matters, you need to understand how browsers render pages.
When a browser receives your HTML, it starts parsing it from top to bottom. When it encounters a <link> tag pointing to a CSS file, it stops rendering and waits for that entire CSS file to download and parse. This is called render-blocking behavior.
Here’s what that means in practice:
- Your CSS file is 150KB and takes 800ms to download on a 4G connection
- The browser won’t paint a single pixel until that file is fully downloaded and parsed
- Your visitor stares at a blank white screen for nearly a full second before seeing anything
- On slower connections, which are more common than you think, this delay gets much worse
Now consider that many websites load multiple CSS files: a framework like Bootstrap, a theme stylesheet, custom styles, maybe a plugin or two. Each one blocks rendering until it’s fully loaded.
The result is what we call a Flash of White, that uncomfortable blank screen that makes visitors wonder if the site is broken. And Google measures this. Your Largest Contentful Paint (LCP) score takes a direct hit every time CSS blocks rendering unnecessarily.
What Is Critical CSS?
Critical CSS is the minimum set of styles required to render the above-the-fold content of a specific page. “Above the fold” means whatever is visible in the browser viewport before the user scrolls.
For a typical homepage, critical CSS might include:
- Reset and base styles (typography, box-sizing)
- Header and navigation styles
- Hero section layout and styling
- Any fonts or colors visible immediately
- Basic grid or layout framework styles
What it wouldn’t include:
- Footer styles (below the fold)
- Styles for elements on other pages
- Hover states for elements not yet visible
- Animation styles that trigger on scroll
- Print stylesheets
By extracting just the critical styles and inlining them in the <head> of your HTML, the browser can start rendering immediately without waiting for external CSS files. The full stylesheet then loads asynchronously in the background, applying remaining styles as it arrives.

The Technical Implementation
Here’s how the approach works at a technical level.
Step 1: Inline Critical CSS in the Head
Instead of linking to your CSS file the traditional way, you embed the critical styles directly:
<head>
<style>
/* Critical CSS inlined here */
body { margin: 0; font-family: system-ui, sans-serif; }
.header { background: #1a1a2e; padding: 1rem; }
.hero { min-height: 60vh; display: flex; align-items: center; }
/* ... more above-the-fold styles ... */
</style>
</head>Because these styles are part of the HTML document itself, the browser has them immediately, no additional network request required.
Step 2: Defer the Full Stylesheet
The complete stylesheet still needs to load, but it doesn’t need to block rendering. You load it asynchronously:
<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 tells the browser to start downloading the CSS file immediately (preload) but not to block rendering while it does. Once the file is downloaded, the onload handler switches it to a regular stylesheet, and all remaining styles apply instantly.
The <noscript> fallback ensures the stylesheet loads normally for users without JavaScript, a small but important accessibility consideration.
Step 3: Handle the Flash of Unstyled Content
One concern with this approach is a potential Flash of Unstyled Content (FOUC), where below-the-fold elements briefly appear unstyled before the full CSS loads. In practice, this is rarely noticeable because:
- The full CSS usually loads within milliseconds of the critical CSS rendering
- Below-the-fold content isn’t visible until the user scrolls
- The critical CSS handles the most visually important elements
However, if you notice FOUC issues, you can add a small amount of non-critical styles to your inline block or use a loading indicator for below-fold sections.
Extracting Critical CSS: Manual vs. Automated
Here’s where it gets practical. You have two approaches to identifying which styles are critical.
The Manual Approach
You can manually identify and extract critical styles by:
- Loading your page in a browser
- Identifying every element visible above the fold
- Tracing the CSS rules that style those elements
- Copying those rules into an inline style block
This works for simple sites with one or two page templates. But it’s tedious, error-prone, and becomes a maintenance nightmare. Every time you update your CSS, you need to update the critical CSS extraction too.
We don’t recommend this approach for most projects.
The Automated Approach
Automated tools analyze your page, determine which CSS rules affect above-the-fold content, and extract them for you. This is the approach we use for every project.
Critical (by Addy Osmani): The most widely used tool for this purpose. It’s a Node.js module that uses headless Chrome to render your page and determine which styles are critical.
const critical = require('critical');
critical.generate({
base: 'dist/',
src: 'index.html',
css: ['dist/styles/main.css'],
width: 1300,
height: 900,
inline: true
});Penthouse: Another popular option that focuses specifically on extracting above-the-fold CSS. It’s fast and works well in build pipelines.
PurgeCSS + Critical: A powerful combination. PurgeCSS first removes any unused CSS from your entire stylesheet, then Critical extracts just the above-the-fold portion. This one-two punch can reduce your initial CSS payload dramatically.
Critters (by Google): Designed specifically for single-page applications. It inlines critical CSS during the build process and works seamlessly with webpack.
Integrating Critical CSS Into Your Build Process
For critical CSS to be practical, it needs to be part of your build process, not a manual step you remember to do before deploying.
With Webpack
If you’re using webpack, the Critters plugin handles this automatically:
const Critters = require('critters-webpack-plugin');
module.exports = {
plugins: [
new Critters({
preload: 'swap',
inlineThreshold: 0,
minimumExternalSize: 0
})
]
};Every time you build your project, Critters analyzes each HTML page, extracts critical CSS, inlines it, and defers the rest.
With Gulp
For projects using Gulp as a task runner:
const critical = require('critical').stream;
gulp.task('critical', function () {
return gulp.src('dist/*.html')
.pipe(critical({
base: 'dist/',
inline: true,
css: ['dist/css/main.css']
}))
.pipe(gulp.dest('dist'));
});With Static Site Generators
Most modern static site generators (Eleventy, Hugo, Astro) can integrate critical CSS extraction as a post-build step. We typically run the Critical library as a post-build script that processes every generated HTML file.
With WordPress
WordPress makes this more challenging because pages are generated dynamically. Options include:
- WP Rocket: includes built-in critical CSS generation
- Autoptimize: can generate and inline critical CSS
- Custom solutions: using the REST API to pre-generate critical CSS for each template type
For most WordPress sites, a quality caching plugin with critical CSS support is the most practical approach.
Handling Multiple Page Templates
One challenge with critical CSS is that different pages have different above-the-fold content. Your homepage hero section has completely different styles than your blog listing page or your contact form.
The solution is generating critical CSS per template, not per page:
- Homepage: hero section, featured content styles
- Blog listing: post grid or list styles
- Blog post: article typography, featured image styles
- Service pages: service card or section styles
- Contact page: form styles, map embed styles
For most small business websites, you’re looking at five to eight templates. Generating critical CSS for each is manageable and covers the vast majority of your pages.
Measuring the Impact
After implementing critical CSS, here’s what you should measure:
Largest Contentful Paint (LCP)
This is the primary metric that critical CSS improves. LCP measures when the largest visible element finishes rendering. By inlining critical CSS, you remove the render-blocking delay that pushes LCP later.
What we typically see: LCP improvements of 500ms to 1.5 seconds, depending on the original CSS file size and connection speed.
First Contentful Paint (FCP)
FCP measures when the first piece of content renders. Critical CSS directly improves this by allowing the browser to start painting immediately.
What we typically see: FCP improvements of 300ms to 1 second.
Cumulative Layout Shift (CLS)
Properly implemented critical CSS can also improve CLS by ensuring layout-defining styles are available immediately, preventing the page from jumping around as styles load.
Time to Interactive (TTI)
By reducing the amount of render-blocking CSS, you free up the main thread sooner, which can improve TTI, especially on mobile devices.
Common Pitfalls and How to Avoid Them
We’ve implemented critical CSS on dozens of projects. Here are the mistakes we see most often:
Extracting Too Little CSS
If your critical CSS misses styles for above-the-fold elements, those elements will flash or shift when the full stylesheet loads. Be sure your viewport configuration for the extraction tool matches common device sizes.
Fix: Test on multiple viewport sizes and include styles for both mobile and desktop above-the-fold content.
Extracting Too Much CSS
If you inline too much CSS, you negate the performance benefit. The goal is to inline only what’s needed, not half your stylesheet.
Fix: Keep inlined critical CSS under 14KB if possible. This fits within the initial TCP congestion window, meaning it arrives in the first network round trip.
Forgetting About Web Fonts
Font declarations in your critical CSS will trigger font downloads. If those fonts block rendering (which they do by default), you might not gain as much as expected.
Fix: Use font-display: swap in your @font-face declarations so text renders immediately with a fallback font while the custom font loads.
Not Updating Critical CSS When Designs Change
If you extract critical CSS once and never update it, design changes will eventually cause visual issues.
Fix: Make critical CSS extraction part of your automated build process so it regenerates with every deployment.
Ignoring Dynamic Content
Pages with dynamic above-the-fold content (A/B tests, personalized content, conditional layouts) can make critical CSS extraction tricky because the above-the-fold content changes.
Fix: Generate critical CSS for the most common or default state, and include styles for likely variations in the critical set.
Real-World Results
We recently implemented critical CSS for a local service business whose WordPress site had a 3.2-second LCP on mobile. Their full CSS payload was 340KB across four stylesheets: the theme, two plugins, and custom styles.
After implementing critical CSS:
- Inlined critical CSS: 11KB (gzipped)
- Deferred full CSS: loaded asynchronously
- LCP dropped from 3.2 seconds to 1.4 seconds
- FCP dropped from 2.1 seconds to 0.8 seconds
- PageSpeed Insights mobile score went from 44 to 78
The site felt dramatically faster. Same design, same content, same hosting. Just smarter CSS delivery.
Is Critical CSS Worth the Effort?
For most websites, absolutely yes. The implementation cost is low (especially with automated tools), the maintenance is minimal (if it’s in your build process), and the performance gains are significant.
The biggest beneficiaries are:
- WordPress sites with heavy themes and multiple plugin stylesheets
- E-commerce sites where every millisecond of load time affects conversion rates
- Mobile-first sites where users are often on slower connections
- Any site scoring poorly on Core Web Vitals due to render-blocking CSS
If your website loads a CSS file over 50KB and your LCP is above 2.5 seconds, critical CSS should be near the top of your optimization list.