/ โ† CSS Checker Fixes / Unused CSS
In this guide
  1. Why unused CSS matters, and when it does not
  2. Where unused CSS comes from
  3. Measuring unused CSS properly
  4. The fix, step by step
  5. Setting up PurgeCSS safely
  6. Platform and framework notes
  7. Mistakes that break sites
  8. Questions and answers

Why unused CSS matters, and when it does not

Every byte of CSS in a stylesheet linked from the page head has to download and be parsed before the browser draws anything. Unused rules also add work when the browser matches selectors against elements. On a fast laptop that cost is small; on a mid-range phone on a patchy mobile connection it shows up as a longer blank screen.

Whether it is worth your time depends on three things:

SituationPriorityReason
A large stylesheet blocks rendering and most of it is unused on key pagesHighVisitors wait for bytes they never use
A whole framework is loaded for a few componentsHighOften the single biggest source of dead rules
A modest shared stylesheet is partly unused on each page but used across the siteLowIt is cached after the first visit and splitting may cost more than it saves
Unused CSS loads after first paintLowIt does not hold up the first view

The CSS Checker estimates how much of your CSS goes unused. Read that estimate together with file size and whether the file is render-blocking: a high percentage of a tiny file is not worth a day's work, while a moderate percentage of a very large blocking file might be. If you have not yet dealt with render-blocking, Fixing render-blocking CSS is often the better first job.

Where unused CSS comes from

Knowing the source tells you the safest fix. Most sites have a mix of these:

The first two are best fixed by importing only the parts you use. The middle three are best fixed by deleting or conditionally loading. Duplicates are fixed by merging. Automated trimming tools help with all of them but are a safety net, not a replacement for understanding what is there.

Measuring unused CSS properly

The Coverage panel

In Chrome or Edge, open developer tools, open the command menu with Ctrl+Shift+P (or Cmd+Shift+P on a Mac), type "coverage" and choose Show Coverage. Click the reload button in the panel. You get a list of every CSS and JavaScript file with its total size and the bytes that went unused. Filter the list to CSS. Clicking a file opens it in the Sources panel with a coloured bar beside each rule: one colour for rules that matched, another for rules that did not.

That view is where most people stop, and it is where the mistakes start. Coverage records what matched while you were watching. If you did not open the mobile menu, the menu styles are "unused". If you did not submit a form with an error, the error styles are "unused". If you were logged out, the account area styles are "unused".

Recording a realistic session

Keep the Coverage panel recording while you work through a checklist on each key template:

  1. Load the page at a phone width, then resize to tablet and desktop widths so each media query applies.
  2. Open and close every menu, accordion, tab set, modal and cookie banner.
  3. Hover and focus links, buttons and form fields, including keyboard focus.
  4. Submit forms empty to trigger validation messages, and complete one to see the success state.
  5. Switch colour scheme if you support dark mode, and turn on reduced motion if you have rules for it.
  6. Repeat logged in, with items in a basket, or in any other state that changes the page.

Export the coverage result from the panel so you can compare it with later runs.

Automating the measurement

For larger sites, a headless browser can collect CSS coverage for a list of URLs and a script of interactions. Puppeteer and Playwright both expose CSS coverage in Chromium, so you can combine many pages into one list of selectors that were used somewhere. That combined list is far more trustworthy than a single page view.

// coverage.mjs: collect used CSS ranges across several pages (Puppeteer)
import puppeteer from 'puppeteer';

const urls = [
  'https://example.co.uk/',
  'https://example.co.uk/services/',
  'https://example.co.uk/contact/'
];
const browser = await puppeteer.launch();
const page = await browser.newPage();
const results = [];
for (const url of urls) {
  await page.coverage.startCSSCoverage();
  await page.goto(url, { waitUntil: 'networkidle0' });
  await page.click('.menu-toggle').catch(() => {});
  results.push(...await page.coverage.stopCSSCoverage());
}
await browser.close();
console.log(JSON.stringify(results.map(r => ({ url: r.url, ranges: r.ranges })), null, 2));
โš ๏ธ Coverage also treats rules for other pages as unused. A rule that is unused on the home page but used on the checkout is not dead. Only rules unused across every page and state you care about are candidates for deletion.

The fix, step by step

Step 1

Measure coverage on your key templates

Run the CSS Checker to see which stylesheets carry the most unused CSS and how large they are. Then open the Coverage panel in Chrome developer tools and reload each key template: home, a main service or product page, a category or listing page, a blog post and the contact or checkout page. Note each stylesheet, its total size and its unused bytes, and focus first on large files that block rendering.

Step 2

Record the interactive states too

Keep coverage recording while you resize through phone, tablet and desktop widths, open menus and modals, focus fields with the keyboard, trigger form errors and success messages, and view the site logged in if that changes anything. Rules that only appear in these states will otherwise look unused. For larger sites, script the same journey in Puppeteer or Playwright and merge the results so you have one list of rules that were used anywhere.

Step 3

Sort the unused rules by where they came from

Group the unused rules into frameworks loaded whole, icon or font libraries, plugin or app styles, theme options you do not use, duplicates and your own leftovers. The group decides the fix. Frameworks and icon sets usually allow importing only the parts you use. Plugin styles can often be loaded only on the pages that need them. Your own leftovers and duplicates can simply be deleted once you have confirmed they are dead.

Step 4

Delete dead rules at source

Search the whole codebase, including templates, JavaScript and CMS content, for each class name before removing a rule, because a class can be added by a script or typed into a page editor. Remove confirmed dead rules from the source files, not from compiled output, so the next build does not bring them back. Replace full framework imports with the individual modules you use, and swap icon fonts for inline SVG or a subset.

Step 5

Automate trimming with a safelist

Add PurgeCSS to your build, or rely on your utility framework's own source scanning, and point it at every file that can contain a class name, including JavaScript and templates. Build a safelist for classes that are created at runtime, such as is-open, has-error, state classes from sliders and anything assembled from strings. Compare the trimmed file size with the original and keep the report for the next review.

Step 6

Test the pages and states you recorded

Work through the same checklist you used for coverage on the trimmed build: every template, every screen width, menus, modals, form errors, logged-in views and dark mode. Compare screenshots before and after where you can. Anything that lost its styling points to a missing safelist entry or a content path the tool did not scan. Then run the CSS Checker again and confirm the unused share has fallen without new visual problems.

Setting up PurgeCSS safely

PurgeCSS reads your content files, extracts every string that looks like a class name, and removes rules whose selectors do not match any of them. It works as a PostCSS plugin, a command-line tool, or through plugins for common bundlers.

// postcss.config.mjs
import purgecss from '@fullhuman/postcss-purgecss';

export default {
  plugins: [
    purgecss({
      content: [
        './src/**/*.html',
        './src/**/*.{js,jsx,ts,tsx,vue}',
        './templates/**/*.twig'
      ],
      safelist: {
        standard: ['is-open', 'is-active', 'has-error', /^swiper-/],
        deep: [/^prose$/],
        greedy: [/tooltip/]
      },
      keyframes: true,
      fontFace: true
    })
  ]
};

The three safelist types behave differently. standard keeps selectors that match; deep also keeps everything nested inside a matching parent, which suits rich-text areas where editors can use any element; greedy keeps any selector that contains a match anywhere. The keyframes and fontFace options remove unused animations and font declarations as well as rules.

Protecting blocks in the stylesheet

For a section of CSS that must never be trimmed, such as styles for content pasted in by editors, wrap it in special comments:

/* purgecss start ignore */
.wysiwyg table { border-collapse: collapse; }
.wysiwyg blockquote { border-left: 4px solid #cbd5e1; }
/* purgecss end ignore */

The dynamic class problem

PurgeCSS and similar tools read your files as text. They cannot see a class name that only exists once code runs. This pattern will lose its styles:

// Class assembled at runtime: the tool never sees "alert-warning"
el.className = 'alert-' + level;

Either write the full names somewhere the tool can see them, for example in a lookup object such as { warning: 'alert-warning', error: 'alert-error' }, or add them to the safelist. The same applies to classes chosen in a CMS, returned from an API, or added by third-party scripts.

Platform and framework notes

Utility-first frameworks

Tailwind CSS generates only the classes it finds in your source files, so unused utilities are not the problem there. What goes wrong is detection: class names built from string fragments, content in folders the scanner does not look at, or files excluded by your ignore rules. Recent versions detect sources automatically and let you add paths with the @source directive; older versions use the content array in the config file. In both cases the fix for a missing style is to write the complete class name somewhere the scanner reads.

WordPress

Much WordPress unused CSS comes from plugins that load styles on every page. Performance plugins offer "remove unused CSS" features that generate trimmed CSS per page; they work, but test logged-in views, forms and WooCommerce pages carefully, and clear their cache after any design change. Loading plugin styles only where needed is often cleaner; see CSS in WordPress themes.

React and other component frameworks

Component-scoped CSS, such as CSS Modules, tends to be split along with the components that import it, so pages only load what their components need. Leftover global stylesheets and whole UI libraries are the usual source of unused CSS in these apps; the React and Next.js guide covers this.

Static sites with no build step

You can still run PurgeCSS once from the command line against your HTML files and stylesheet, review the output, and upload the trimmed file. Keep the original so you can compare and restore.

Mistakes that break sites

๐Ÿ’ก Keep a short written list of "pages and states to test", and use the same list for measuring, for safelisting and for checking the result. It turns a risky clean-up into a repeatable routine.
Questions and answers

1. How much unused CSS is acceptable?

There is no official threshold. Some unused CSS on every page is normal, because one stylesheet serves many templates and states. Focus on the combination of size and timing: a large render-blocking stylesheet where most of the bytes go unused on your key pages is worth fixing, while a small cached stylesheet that is partly unused on each page usually is not. Compare your key templates, not just the home page, before deciding how far to go.

2. Why does the Coverage panel say most of my CSS is unused?

Coverage only records rules that matched during the time you were watching, on that one page, at that screen width, in that state. Styles for other pages, mobile or desktop layouts you did not view, menus you did not open, form errors you did not trigger and logged-in areas all count as unused. The figure is a useful starting point, but record a full session across widths and states before treating anything as genuinely dead.

3. Is PurgeCSS safe to use on a live site?

It is safe when it is set up carefully and tested. The risk comes from class names it cannot see, such as ones added by JavaScript, built from strings, chosen in a CMS or injected by third-party widgets. Point it at every file that can contain class names, safelist runtime classes and editor content areas, and test every template and interactive state on the trimmed build before deploying. Keep the untrimmed stylesheet so you can roll back quickly.

4. Does unused CSS affect SEO?

Not directly. Search engines do not penalise a page for carrying style rules it does not use. The effect is indirect: a large render-blocking stylesheet can delay the first paint and the main content appearing, which affects how visitors experience the page and can show up in speed measurements such as Largest Contentful Paint. Remove unused CSS because it makes pages faster for real people, especially on phones, not because of a ranking rule.

5. Why did styles disappear after I removed unused CSS?

The trimming tool removed rules for class names it could not find in the files it scanned. Common causes are classes added by JavaScript, class names assembled from fragments, content folders missing from the scan paths, classes typed into a page editor and markup injected by third-party widgets. Find the affected element, note its classes, and either add those names to the safelist or write them in full somewhere the tool reads, then rebuild and retest.

6. Should I remove unused CSS or inline critical CSS first?

If your stylesheet is blocking the first paint, deal with that first by inlining the critical rules for each template and loading the rest without blocking. That changes what visitors wait for most directly. Removing unused CSS then shrinks what remains and makes both the inlined and deferred parts smaller. On a site where CSS is already loaded efficiently, trimming unused rules is still worthwhile housekeeping but will usually make less visible difference.

7. Can I remove unused CSS in WordPress without coding?

Yes. Several performance plugins include a remove unused CSS feature that builds a trimmed stylesheet for each page automatically. They save a lot of manual work, but test forms, menus, logged-in views, WooCommerce pages and anything that changes after the page loads, because those are where styles go missing. Clear the plugin's cache after design changes. Many sites also gain a lot simply by stopping plugins from loading their styles on pages where they are not used.

See how much of your CSS goes unused

The CSS Checker estimates how much of your CSS goes unused and measures stylesheet size, alongside W3C validation, render-blocking stylesheets, specificity issues and prefix gaps.

Open CSS Checker Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All CSS Checker Fixes  ·  Fixing Render-Blocking CSS  ·  Fixing Oversized Stylesheets  ·  CSS Checker Guide  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.