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.
<div class="container">
<div class="card">
<h1 class="title">Hello World</h1>
<p class="text">This is a sample.</p>
</div>
</div> .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;
} .container {
max-width: 1200px;
margin: 0 auto;
}
.card {
background: white;
padding: 2rem;
}
.title {
font-size: 2rem;
color: #333;
} 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.
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.
# 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.
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.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.
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.
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.
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.
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.
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.
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.
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.
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.