What the CSS Coverage Analyzer does
This checker matches every selector in a stylesheet against HTML samples of your pages and sorts the rules into used, uncertain and unused - conservatively. A rule is only called unused when nothing in the samples could match it even allowing for states; anything that depends on hover, focus, classes that scripts toggle, print, CSS nesting or your safelist is marked uncertain instead. It also lists critical-CSS candidates: used rules that style the top of the page.
Pasted CSS and HTML are analysed in your browser; the HTML is parsed with an inert DOMParser and never rendered. A public URL can be checked instead - the a2z.tools server fetches the page and up to four stylesheets - but one page is only one sample.
How to use it
- Paste the stylesheet you want to slim down into the CSS box.
- Paste the HTML of every page type that uses it - home, article, listing, form, account, error page - separated by a line containing
<!-- page -->. Use the rendered HTML (View Source for server-rendered sites, or copy the Elements panel's outer HTML for client-rendered ones). - Add safelist patterns for classes your framework or CMS adds at run time, such as
.swiper*or.toast*. - Press Check coverage and start with the unused list: search your codebase for each selector before deleting it.
- Test the uncertain rules by using the page - hover, open menus, submit forms - and copy the critical-CSS candidates if you plan to inline above-the-fold styles.
Reading the results
Used means at least one selector of the rule matches an element in at least one sample. A state selector such as .nav a:hover counts as used when .nav a exists, because the state can happen.
Uncertain means the samples cannot settle it: a state selector whose element is missing, a class that scripts usually add (is-open, active, [aria-expanded]), a vendor-prefixed selector, a nested rule, a print style, or a safelisted pattern.
Unused means no selector matched anything in any sample. That is strong evidence for these samples only - templates you did not paste, emails, admin pages and content from a CMS can still need the rule.
At-rules without selectors (@font-face, @keyframes, @page) are kept and never reported as unused; whether a font or animation is referenced is a separate question.
Critical candidates are used rules that match one of the first 60 elements of a sample - an A2Z heuristic for "near the top of the page", not a measurement of the viewport.
Worked example: a blog theme checked against a home page and an article
The example theme has 33 style rules plus a @font-face and a @keyframes. Against the two pages, 24 rules are used, 2 are uncertain and 7 are unused.
The unused rules are .newsletter-popup, .carousel .slide, .btn-danger, .legacy-sidebar (twice, once inside the 720 px media query), .legacy-sidebar .widget and .ie-only-fix - 304 bytes, 17% of the file before compression. The popup may still be injected by a script, so it is worth a search before deleting; the legacy sidebar and the IE fix are safe bets.
.nav.is-open and .carousel .slide.active are uncertain because scripts normally add those classes, and the hover and focus rules count as used because their elements exist. No rule was removed on the strength of a single page.
Why coverage tools over-report unused CSS
Browser coverage panels and most online checkers look at one page in one state. They mark rules for other templates, for hover and focus, for open menus and modals, for error messages and for print as unused - and deleting them breaks the site in places nobody tested. This tool treats those cases as uncertain and says why, so the unused list is short and trustworthy.
The saving from removing dead CSS is usually modest after compression, because repetitive CSS compresses well. The bigger performance win is often inlining the small set of critical rules and loading the rest without blocking rendering.
Limitations: what the result does not prove
- Results are only as good as the samples. Rules for pages, states and content you did not include will look unused.
- Selectors are matched with the browser's own querySelector on static HTML. Viewport, media queries and computed styles are not evaluated; a rule inside
@media (min-width: 1200px)is judged by its selector alone. - Shadow DOM, iframes and HTML generated by scripts after load are not seen unless you paste the rendered HTML.
- The URL mode reads one page and at most four stylesheets from the a2z.tools server; stylesheets on other origins that block our fetcher are reported as not read.
Privacy: where your data goes
The analysis runs in your browser. If you choose to load a public URL instead of pasting, a2z.tools fetches that address read-only and returns the text to your tab; private and internal addresses are refused and nothing is stored. Session recording and tag-manager scripts are switched off on this page.
Standards and sources
- MDN - Document.querySelector()
- W3C Selectors Level 4
- web.dev - Extract critical CSS
- Chrome for Developers - Coverage panel
Frequently asked questions
Is it safe to delete CSS rules marked unused?
Only after checking. Unused means no pasted page matched the selector. Search your templates, scripts and CMS content for the class names first; pages and states you did not include can still depend on them.
Why are hover and focus rules not reported as unused?
A static HTML sample never hovers or focuses anything. If the element exists, the state can happen, so the rule is counted as used; if the element is missing, the rule is marked uncertain rather than dead.
How is this different from the Coverage panel in Chrome DevTools?
DevTools records which rules one page used during one session, which is precise for that visit. This tool combines several page samples, explains each verdict, and refuses to call state-dependent or script-dependent rules unused.
What is critical CSS?
It is the small set of rules needed to render the top of the page. Inlining it in the HTML head lets the first paint happen without waiting for the full stylesheet, which can improve LCP. The rest of the CSS then loads without blocking.
Does it understand @media, @supports and @layer?
Yes. Rules inside those blocks are evaluated like any other and shown with their condition. The condition itself is not evaluated, because the samples have no viewport or browser features to test against.
Can I check CSS for a site built with Tailwind or CSS-in-JS?
Tailwind builds normally purge unused utilities already, so expect few results. For CSS-in-JS, paste the generated stylesheet and the rendered HTML; class names that change per build must be taken from the same build.
Last reviewed by the A2Z.Tools team against the sources listed above.