About the CSS Minifier
A CSS minifier should make your stylesheet smaller and change nothing else. This one removes comments, line breaks and indentation, and leaves alone every space that carries meaning: inside strings and url() paths, around the minus in calc(100% - 2rem), after and in a media query, and in a selector like .nav :hover.
It reads the CSS with a tokenizer, not search-and-replace, so it knows where a string or comment really ends. Values stay as you typed them and rules keep their order, so the output is the same stylesheet with less whitespace. Format mode does the reverse with Prettier. Both run in your browser.
- Paste your stylesheet into Input CSS, or click Load Example for one with a license comment,
url(),calc(), nesting and a media query. - Minify is already selected, so Minified CSS fills in as soon as you pause, with Original Size, Minified Size and Savings above it.
- If a brace is missing, or a comment, string or
url(is never closed, CSS Error replaces the output and gives the position, for exampleLine 1, column 4: "{" is never closed. That line number turns red in the input. - Click Format to read minified CSS. Prettier's version appears in Formatted CSS, and your input stays as it is.
- Copy the result, or download it as
minified.cssorformatted.css.
Input/*! MyLib v1.0 | MIT License */
/* Card component */
.card {
padding: 16px;
margin: 0 auto;
border: 1px solid #ddd;
}
.card > .title,
.card .nav :hover {
color: #333;
}Output/*! MyLib v1.0 | MIT License */ .card{padding:16px;margin:0 auto;border:1px solid #ddd}.card>.title,.card .nav :hover{color:#333}
177 B → 129 B, 27.1% savedThe space in .nav :hover stays. Without it the selector would mean a hovered .nav, not a hovered element inside it.
Input.sidebar {
width: calc(100% - 2rem);
margin-top: calc(var(--gap) * -1);
content: "a : b";
}
@media screen and (min-width: 768px) and (prefers-color-scheme: dark) {
.grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem 2rem;
}
}Output.sidebar{width:calc(100% - 2rem);margin-top:calc(var(--gap) * -1);content:"a : b"}@media screen and (min-width: 768px) and (prefers-color-scheme: dark){.grid{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1rem 2rem}}
274 B → 233 B, 15.0% savedThe double spaces inside the string are text the page shows, so they stay. The space after each and stays too.
Input@layer base, components;
@layer components {
.btn {
color: white !important;
background: oklch(62% 0.19 255);
&:hover:not(.is-disabled) {
background: oklch(55% 0.19 255);
}
.icon + & {
margin-left: 4px;
}
}
}Output@layer base,components;@layer components{.btn{color:white !important;background:oklch(62% 0.19 255);&:hover:not(.is-disabled){background:oklch(55% 0.19 255)}.icon + &{margin-left:4px}}}
251 B → 185 B, 26.3% savedInput.hero {
background-image: url(https://cdn.example.com/img/hero//banner.jpg), url(data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>);
}
.quote::before {
content: "\201C";
}
@font-face {
font-family: "Noto Sans JP";
src: url("/fonts/noto-sans-jp.woff2") format("woff2");
}Output.hero{background-image:url(https://cdn.example.com/img/hero//banner.jpg),url(data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>)}.quote::before{content:"\201C"}@font-face{font-family:"Noto Sans JP";src:url("/fonts/noto-sans-jp.woff2") format("woff2")}
296 B → 266 B, 10.1% savedThe // inside the unquoted URLs isn't mistaken for a comment, and the \201C escape (a curly opening quote) is copied as written.
Which spaces in CSS are safe to remove
Most whitespace in a stylesheet is there for people. A few spaces change what the browser reads, and removing them breaks the page in ways that are hard to trace:
- Between selectors.
.nav :hovermatches a hovered element inside.nav;.nav:hovermatches.navitself. - Around
+and-incalc().calc(50% - 8px)subtracts, whilecalc(50% -8px)is invalid, because-8pxreads as a negative number with no operator before it. - After
andin a media query.and (min-width: 768px)works, butand(reads as a function name and the browser drops the whole query. - Between values.
margin: 0 autoandgap: 1rem 2remneed the space to tell the values apart. - Inside strings and URLs.
content: "a : b"shows its spaces on the page, and a URL can contain//or,.
What gets removed
The minifier removes /* */ comments (not /*! */ license comments), line breaks, indentation, spaces around {, }, ;, ,, > and each declaration's colon, the last ; before } and doubled ;.
Nothing else changes. #ffffff stays #ffffff, 0px stays 0px, two rules for one selector stay two rules, and an empty .a{} stays. That's deliberate: an optimizer saves more by rewriting values and merging rules (the In code tab shows how much), but then the output is no longer the CSS you tested.
Why minify CSS
Stylesheets in the <head> block rendering: the browser shows nothing until it has downloaded and parsed them, so fewer bytes there means a faster first paint on slow connections.
Server compression adds to the saving. Prism 1.30.0's default theme, prism.css, is 2,335 bytes, and 1,827 minified here. Gzipped, that's 683 bytes instead of 893; with Brotli, 569 instead of 738. For a bigger win, open the Coverage panel in Chrome DevTools: unused rules often cost more than whitespace.
If your site has a build step, let it minify (see In code). This page is for one-off jobs: the custom CSS box of a CMS or theme, a <style> block for an HTML email, or reading a vendor's minified file. For markup and scripts, use the HTML Minifier and the JavaScript Minifier.
The same stylesheet through three minifiers
A 174-byte stylesheet, minified here, with esbuild 0.28 and with Lightning CSS 1.33. esbuild rewrote every value it could: #ffffff to #fff, four zeros to 0, and rgba(255, 0, 0, 0.4) to #f006, a hex form that very old browsers don't understand. Lightning CSS, told to support browsers with at least 0.25% usage, kept rgba() and merged the two .box rules into one.
On a real file the gap is small. Prism ships its own prism.min.css, made by an optimizer that writes black as #000 and drops the quotes in [class*="language-"]. It's 1,789 bytes: 38 bytes less than this page's 1,827, and 5 bytes less after gzip.
.box {
color: rgba(255, 0, 0, 0.4);
margin: 0px 0px 0px 0px;
background: #ffffff;
}
.box { padding: 8px; }
@media screen and (min-width: 768px) { .box { color: red } }.box{color:rgba(255,0,0,0.4);margin:0px 0px 0px 0px;background:#ffffff}.box{padding:8px}@media screen and (min-width: 768px){.box{color:red}}.box{color:#f006;margin:0;background:#fff}.box{padding:8px}@media screen and (min-width:768px){.box{color:red}}.box{color:rgba(255,0,0,.4);background:#fff;margin:0;padding:8px}@media screen and (min-width:768px){.box{color:red}}Minify CSS in a build step
These are the commands that produced the outputs above. Set browser targets when you use an optimizer, so it doesn't write color syntax your oldest supported browser can't read.
npx lightningcss-cli --minify --bundle --targets ">= 0.25%" input.css -o output.cssnpx esbuild input.css --bundle --minify --outfile=app.min.cssnpx prettier . --writeIs it safe to minify CSS?
Yes, as long as the minifier understands CSS syntax. This one never touches strings, url() values or escapes, and it keeps the spaces in selectors, calc() and media queries that change meaning, so the page renders the same.
Why aren't colors like #ffffff shortened to #fff?
Values are never rewritten here, so what you tested is what ships. Shortening colors, zeros and units saves a few more bytes; if you want that, use an optimizer such as Lightning CSS or esbuild in your build.
How do I unminify CSS?
Paste it and click Format. Prettier puts every rule and declaration on its own line with two-space indents. Comments that were removed during minifying can't come back.
Does it support nesting, @media, @layer and @supports?
Yes. Nested rules like &:hover { } and @media, @supports, @layer, @font-face and @keyframes blocks are minified like any other rule, and the space after the colon in (min-width: 768px) is kept.
How do I keep a license comment?
Start it with /*! instead of /*. Normal comments are removed and /*! */ comments stay, which is the same convention most minifiers follow.
What does "{" is never closed mean?
The braces don't balance. The error points to the opening brace that's still open at the end of the file, so look for its missing }. Braces inside strings and comments are ignored when counting.