
Remove Unused CSS: How to Find and Fix It
TL;DR — This audit fires when a stylesheet ships far more rules than the page actually uses, so the browser downloads, parses, and builds a style tree for selectors that never match a single element. Because CSS is render-blocking by default, that dead weight delays first paint and Largest Contentful Paint for zero visual payoff.
What this check flags
Lighthouse reports the number of bytes in each stylesheet that the current page never applies. A framework like Bootstrap or a bloated theme stylesheet might ship 300 KB of rules while a given landing page touches maybe 15 KB of them. Every byte still has to arrive, get parsed into the CSSOM, and be matched against the DOM before the browser will paint anything — so unused CSS is a tax paid up front, on the critical path, every single load.
A real example, and the fix
A marketing page pulls the entire framework build in the <head>:
<link rel="stylesheet" href="/css/bootstrap.min.css"> <!-- 190 KB, ~9,000 selectors -->The page uses a grid, a couple of buttons, and one card. The other 8,900 selectors — carousels, modals, tooltips, badges you never render — still block paint. The fix is to generate a stylesheet scoped to what the page really uses, then inline the above-the-fold slice:
# Build a CSS file containing only selectors this page actually matches
npx purgecss --css bootstrap.min.css --content index.html --output ./dist/
# Result: ~14 KB instead of 190 KB — no visual changeThen inline that critical slice in the <head> and load the rest asynchronously so it never blocks the first paint.
Coverage: how much are you really using?
The DevTools Coverage tab gives you a hard number per file. These ranges are what teams typically see before cleanup — use them to judge whether a stylesheet is worth splitting or just deleting.
| Source | Typical unused CSS | Why it happens | First move |
|---|---|---|---|
| Full framework build (Bootstrap, Foundation) | 85–95% | Ships every component; you use a handful | PurgeCSS against real templates |
| Page-builder / theme bundle | 60–80% | One global stylesheet for every layout | Split per template, load conditionally |
| Design-system utility CSS (untree-shaken) | 40–70% | All utilities emitted, few applied | Enable JIT / content scanning |
| Hand-written app CSS | 10–30% | Old rules for removed features | Coverage tab, then delete dead blocks |
How to detect it
- Lighthouse / PageSpeed Insights: run the audit and open "Reduce unused CSS" under Diagnostics. It lists each stylesheet with the wasted bytes and the potential load savings.
- DevTools Coverage tab: open DevTools, press Cmd/Ctrl+Shift+P, run "Show Coverage," reload the page, and read the red/green bar per file. Red is CSS that never matched — the percentage is your unused figure. Interact with the page (open menus, tabs) so you do not flag rules that only apply after a click.
- Build-time report: run PurgeCSS or your framework's purge step in "rejected" mode to get a list of exactly which selectors were dropped, so you can confirm nothing dynamic got cut.
How to fix it
- Purge dead selectors at build time. Point PurgeCSS (or Tailwind's content scanner) at every template, component, and JS file that can inject class names, so only matched rules survive.
- Split CSS per template. A checkout page should not load blog styles. Ship route-scoped stylesheets instead of one global monolith.
- Inline critical CSS, defer the rest. Put the above-the-fold rules directly in the
<head>and load the remainder with a non-blocking pattern. The critical CSS approach is the standard play. - Safelist dynamic classes. If class names are built in JavaScript at runtime, add them to a safelist so the purge step does not strip styles you still need.
- Watch third-party widgets. Chat, consent, and A/B tools inject their own stylesheets. You often cannot purge them, but you can load them after paint.
Why this is not the same as unused JavaScript
Unused CSS and unused JS both waste bytes, but they hurt in different ways. Unused CSS is render-blocking — the browser refuses to paint until it has parsed the stylesheet, so the cost lands on first paint and LCP. Unused JavaScript costs mostly CPU (parse, compile, execute) and hits interactivity. CSS also cannot be "tree-shaken" the way modules can; you prune it by matching selectors against real markup, not by following import graphs. Because CSS blocks rendering, trimming it often buys a faster visible page than trimming JS of the same size. Both sit on the critical path alongside render-blocking resources, which is why the Eliminate render-blocking resources audit usually lights up at the same time.
FAQ
Will removing unused CSS break my page?
Only if the purge step misses class names that appear at runtime. Test after purging, safelist anything generated in JavaScript, and keep the "rejected selectors" report so you can spot over-eager cuts before they ship.
Is unused CSS the same as unminified CSS?
No. Minification removes whitespace and comments from rules you keep; purging removes rules you never use. They stack — minify CSS the survivors after you have purged the dead ones.
How much does unused CSS actually cost me?
The real cost is on the critical path: parse time plus a delayed first paint, not just download size. Even gzipped, a large stylesheet must be fully parsed into the CSSOM before paint, so trimming it helps LCP more than the raw byte count suggests.
Can I just lazy-load all my CSS?
No — the above-the-fold styles must be present at first paint or you get a flash of unstyled content. Inline the critical slice and defer only the rest.
Does a page builder make this worse?
Usually, yes. Builders ship one global stylesheet covering every possible module, so most pages use a small fraction of it. Per-template splitting is the highest-leverage fix on builder-driven sites.
Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.
About SEO ProCheck
Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.
Work With Me
Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.







