Shrink a stylesheet by removing comments, indentation and the characters browsers do not need. Expect roughly 20 to 40% off hand-written CSS. Rules and their order stay as written, so the cascade does not change.
/* Card component */
.card {
background : #ffffff;
border-radius : 0.75rem;
padding : 1.5rem 2rem;
box-shadow : 0 1px 2px rgba(0, 0, 0, 0.05);
}
.card:hover {
box-shadow : 0 4px 12px rgba(0, 0, 0, 0.08);
} .card{background:#fff;border-radius:.75rem;padding:1.5rem 2rem;box-shadow:0 1px 2px rgba(0,0,0,.05)}.card:hover{box-shadow:0 4px 12px rgba(0,0,0,.08)} Every /* ... */ block goes, including the license header at the top. Keep a copy of the source if that header has to ship.
Newlines, indentation and the spaces around braces, colons, semicolons, commas and the > combinator. The single space inside a shorthand value stays, because it separates the values.
The semicolon before a closing brace, the leading zero in 0.5rem, and #ffffff collapsed to #fff when both halves of each pair match.
Selectors, declarations, at-rules and their order are left as written, with no merging and no reordering. Strings, url() values and calc() expressions are set aside before minifying and put back unchanged.
Run PurgeCSS before you minify. The two solve different problems, and purging usually saves far more. Say a framework build is 300 KB: minifying might take it to 220 KB, while removing the 95% of selectors your markup never uses could take it to 12 KB. Minify whatever survives the purge, which also leaves the minifier far less to process.
# The usual choice: cssnano through PostCSS
npm i -D postcss postcss-cli cssnano
npx postcss src/style.css --use cssnano -o dist/style.min.css
# esbuild, if it is already in the project
npx esbuild src/style.css --minify --outfile=dist/style.min.css
# Tailwind minifies on its own
npx tailwindcss -i src/input.css -o dist/style.css --minify
# Then check what you actually shipped
gzip -c dist/style.min.css | wc -c const postcss = require("postcss");
const cssnano = require("cssnano");
const fs = require("node:fs");
const css = fs.readFileSync("src/style.css", "utf8");
postcss([cssnano({ preset: "default" })])
.process(css, { from: "src/style.css", to: "dist/style.min.css" })
.then((result) => {
fs.writeFileSync("dist/style.min.css", result.css);
console.log(css.length, "->", result.css.length);
});
// The "default" preset is conservative. "advanced" merges rules and
// reorders declarations, which can change the cascade. Read the diff. # pip install csscompressor
from csscompressor import compress
with open("src/style.css") as f:
css = f.read()
minified = compress(css)
with open("dist/style.min.css", "w") as f:
f.write(minified)
print(f"{len(css)} -> {len(minified)} bytes "
f"({100 - round(len(minified) / len(css) * 100)}% smaller)") Compile, purge, minify, then compress, in that order. Compile Sass, purge unused selectors, minify, and let the server gzip or brotli the result. Each step has less to process because the step before removed the bulk. In the other order, the minifier works through 300 KB to save 80 KB that PurgeCSS was about to delete anyway.
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.
Comments, newlines, indentation, the spaces around braces, colons, commas and the > combinator, the last semicolon in a block, and the leading zero in values like 0.5em. It also shortens #ffffff to #fff. Everything that affects rendering stays.
It should not. It leaves selectors and declarations alone and only touches the characters between them. Quoted strings, url() values, data URIs and calc() expressions are set aside first and put back unchanged, whitespace included.
No. Merging duplicate selectors can change the cascade, so rules stay where you wrote them. Use PurgeCSS if you want to remove rules nothing matches.
Usually 20 to 40% on hand-written CSS, and less on a framework build that ships partly minified already. The panel header shows the size before and after, and the percentage saved.
Yes. They work on different things: minifying removes characters, and gzip compresses repetition in what remains. The two together beat either one alone.
To read a minified file again, run it through the CSS formatter. If the stylesheet is large because it is a full framework build, PurgeCSS will save you far more than minifying will. If you write Sass, compile it first with the SCSS compiler.