Purge CSS / CSS Cleaner

Paste your HTML and your stylesheet and get back only the rules that match something in the markup. Use it to answer one question before you set up a build step: how much of that framework are you shipping without using it? The status line reports how many rules were removed and what percentage that is.

Paste your HTML here
Purged CSS

1 Purge CSS example

HTML Input

1
2
3
4
5
6
<div class="container">
  <div class="card">
    <h1 class="title">Hello World</h1>
    <p class="text">This is a sample.</p>
  </div>
</div>

CSS Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.container {
  max-width: 1200px;
  margin: 0 auto;
}
.card {
  background: white;
  padding: 2rem;
}
.title {
  font-size: 2rem;
  color: #333;
}
.unused-class {
  color: red;
  display: none;
}
#unused-id {
  background: blue;
}

Purged CSS Output

1
2
3
4
5
6
7
8
9
10
11
.container {
  max-width: 1200px;
  margin: 0 auto;
}
.card {
  background: white;
  padding: 2rem;
}
.title {
  font-size: 2rem;
  color: #333;
}

2 What the purge tells you

How much CSS you can drop

Measure before you configure a build. Utility frameworks ship thousands of classes, and a single page often uses a few dozen. Removing the rest can take a stylesheet from hundreds of kilobytes down to single digits.

Runtime classes get removed

The tool parses your HTML with DOMParser and tests each selector with querySelector. A class that JavaScript adds later, such as an open state on a modal, is not in that HTML, so its rule is removed. Add those class names to the HTML input before you trust the output.

How to use the Purge CSS tool

  1. On the "1. HTML Content" tab, paste the markup that uses your styles, or click Upload HTML File. Dummy Data fills both tabs with a small example.
  2. Switch to the "2. CSS Content" tab and paste the stylesheet, or click Upload CSS File.
  3. Click Purge CSS. The output panel shows only the rules whose selectors match something in the HTML, and the status line reports how many rules were removed and what percentage of the total that is.
  4. Rules inside @media, @supports, @layer and @container are checked one by one. @font-face, @keyframes and @import are always kept.
  5. Click Copy to copy the result or Download to save it as a file. Clear resets all three panels.

How to remove unused CSS with PurgeCSS in a build

PurgeCSS CLI

# Install once
npm install --save-dev purgecss

# Scan every HTML and JS file, write the purged CSS to dist/
npx purgecss --css src/style.css --content "src/**/*.html" "src/**/*.js" --output dist/

# Keep classes that JavaScript adds at runtime
npx purgecss --css src/style.css --content "src/**/*.html" --safelist is-open is-active --output dist/

We did not run these here because purgecss is not installed in this repository. The commands come from the PurgeCSS documentation.

Node.js API

import { PurgeCSS } from "purgecss";

const results = await new PurgeCSS().purge({
  content: ["src/**/*.html", "src/**/*.js", "src/**/*.vue"],
  css: ["src/style.css"],
  safelist: {
    standard: ["is-open", /^btn-/],   // exact names or patterns
    deep: [/^modal/],                 // keep children of matching selectors
    greedy: [/^tooltip/],             // keep any selector containing the match
  },
  // Tailwind-style classes contain : and /, so widen the extractor
  defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
});

for (const { file, css } of results) {
  console.log(file, css.length, "bytes");
}

Requires the purgecss package (v5 and later are ESM-first). Add rejected: true to the options to list the classes it removed.

PostCSS config

// postcss.config.js
import purgeCSSPlugin from "@fullhuman/postcss-purgecss";

export default {
  plugins: [
    purgeCSSPlugin({
      content: ["./src/**/*.{html,astro,jsx,tsx}"],
      safelist: ["html", "body", /^data-theme/],
    }),
  ],
};

Install @fullhuman/postcss-purgecss. Frameworks such as Tailwind ship their own content scanning, so do not run both.

Common errors and how to fix them

Styles for a modal, dropdown or toast disappear in production
The class is added by JavaScript after page load, so it never appears in the static HTML. Add the class name to the HTML you paste, or safelist it in your build config.
Please provide both HTML and CSS
One of the two tabs is empty. The purge needs markup to compare selectors against, so paste at least the page template on the HTML tab.
Hover, focus and :nth-child styles were removed
Pseudo-classes are stripped before matching, so a:hover is kept only if an a element exists in the HTML. The base element must be present, but the pseudo state itself is not required.
Nearly 0% reduction even though most of the framework is unused
The HTML you supplied contains the full class list, for example a component library demo page, or the CSS is one long minified rule that the tool treats as a single block. Paste only the pages you serve, and format the CSS first.
Classes with slashes or colons such as md:w-1/2 are dropped by PurgeCSS
The default extractor splits on those characters. Use a custom defaultExtractor as in the Node.js snippet, or rely on Tailwind's own content option instead of PurgeCSS.

Good to know

Purging is static analysis: it sees the class names that appear as written in the content you hand it and nothing else. A class assembled at runtime, like `btn-` + variant in a template, or one toggled by a script, never shows up in that content. Safelist those classes, and keep the safelist short and reviewed.

This tool parses your HTML with DOMParser and tests each selector with querySelector, so matching follows real CSS rules instead of string search. If the browser cannot parse a selector, the tool keeps the rule. Treat the result as a preview of what a build-time purge would do, then add PurgeCSS or your framework's own content scanning to the production build.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

How does it decide which CSS is unused?

It parses the HTML you provide with DOMParser and runs each selector through querySelector. A rule is removed when its selector matches no element, so class names, IDs, tag names and attribute selectors all follow real CSS matching.

Will it remove classes added by JavaScript?

Yes, if those class names do not appear in the HTML you paste. Add the dynamic class names to the HTML input, for example a hidden element with class="is-open", or keep those rules by hand.

Are media queries handled?

Yes. Rules inside @media, @supports, @layer and @container blocks are checked one by one, and the at-rule is dropped only when nothing inside it is used. @font-face, @keyframes and @import are always kept.

Can I upload files instead of pasting?

Yes. Use Upload HTML File on the HTML tab and Upload CSS File on the CSS tab, then click Purge CSS. The files are read in the browser and not uploaded to a server.

How much size reduction should I expect?

It depends on the framework and how much of it you use. A full Bootstrap or Tailwind build used by a single page often loses more than 90% of its rules. The status line reports the exact count and percentage of rules removed.

Related

The CSS formatter makes the output readable. If your styles are written in SCSS, run them through the SCSS compiler first to get plain CSS to purge.

More CSS & Design Tools

Browse all css & design tools

Copied to clipboard!