How UnCSS Works

UnCSS employs a sophisticated process to analyze your web pages and stylesheets to determine which CSS is actually in use. Understanding this process can help you use the tool more effectively and troubleshoot any issues that arise.

The Core Process

UnCSS follows four main steps:

1. HTML Loading & JavaScript Execution

First, UnCSS loads your HTML files into a virtual DOM environment powered by jsdom. This is not just a simple HTML parser; jsdom emulates a web browser's environment, complete with window and document objects.

Crucially, it executes the JavaScript found on the page that runs during the initial page load. This allows UnCSS to detect CSS classes and styles that are added, removed, or modified dynamically by your scripts. The DOM that UnCSS analyzes is the one that exists after this initial script execution.

2. Stylesheet Parsing

Next, UnCSS discovers all relevant stylesheets. It finds <link rel="stylesheet"> tags in your HTML and can also be given a list of stylesheets directly via the stylesheets option. It then reads these files and parses them using PostCSS. This converts the raw CSS text into an Abstract Syntax Tree (AST), which is a structured, tree-like representation of the CSS rules, selectors, and properties.

3. Selector Filtering

This is the core of UnCSS's logic. It iterates through every single CSS rule from the AST. For each selector in a rule (e.g., .my-class, #my-id > p), UnCSS uses the document.querySelector method in the jsdom environment to check if any element on the page matches that selector.

  • If document.querySelector('your-selector') returns an element, the selector is considered used.
  • If it returns null, the selector is considered unused.

A CSS rule is kept if at least one of its selectors is found on the page.

4. Clean CSS Regeneration

After checking all selectors, UnCSS filters the PostCSS AST, removing any rules that were found to be completely unused. The modified, lightweight AST is then converted back into a minified CSS string, which is the final output.

Limitations

While powerful, this process has some inherent limitations that are important to be aware of:

  • No User Interaction: UnCSS does not simulate user interactions like clicking buttons, hovering over elements, or scrolling. If your JavaScript adds a class like .is-open only when a user clicks a menu button, UnCSS will not see it and will likely remove the associated styles. This is the primary use case for the ignore option.
  • Non-HTML Files: UnCSS cannot directly process server-side templates (e.g., PHP, ERB, Handlebars). It needs rendered HTML to work. The recommended approach is to either generate static HTML pages from your templates for UnCSS to scan, or run a local development server and point UnCSS to the live URLs.
  • Pseudo-elements & Pseudo-classes: Certain pseudo-classes like :hover, :focus, and :active, and pseudo-elements like ::before and ::after cannot be directly queried in the DOM. UnCSS has special logic to handle these: it checks for the existence of the base selector (e.g., for .button:hover, it checks if .button exists) and preserves the rule if it does. See Ignoring Selectors for more details.