Is CSS Minification Safe? Four Places Whitespace Is Content
Minification is safe when the only thing removed is whitespace between tokens. Everything below is a case where the whitespace is not between tokens, measured against the shipped minifyCss/beautifyCss on this site by running them on the input shown.
1. A semicolon inside a quoted string is content
Input:
a { content: "a; b" }
Beautify output, verbatim:
a {
content:"a;
b"
}
The declaration is now split across lines inside the quotes. The rendered text is unchanged — CSS allows a newline inside a quoted string, so the page still shows a; b — but the file no longer diff-clean and a second pass through any stricter tool can legitimately fail. Cause: replace(/;/g, ";\n ") cannot tell a separator from a character in a string.
Same class, one level nastier — a colon in a string:
.b { content: "x: y" }
minifies to .b{content:"x:y"}. The space after the colon is gone inside the value. The string literally changed from x: y to x:y. Whitespace after : is exactly what a beautifier inserts, which means a beautify→minify cycle removes a space that the original author wrote on purpose.
2. data: URIs are strings full of separators
.i { background: url("data:image/svg+xml;charset=utf8,<svg/> <circle/>"); }
Measured minify output: the whitespace around ; in charset=utf8 is preserved here because the run of spaces sits between > and <, not adjacent to a punctuation token — but the same input with charset=utf8 ; loses it. The behaviour depends on which characters happen to neighbour the whitespace, so the output is neither reliably safe nor reliably broken. That is worse than a guaranteed failure: it passes code review and fails on one icon in production.
If a value carries spaces that matter (SVG in a data URI, content, font-variant-numeric-style fallback stacks), quote it and keep it out of automated minify passes, or ship the SVG as a file.
3. Comments that are load-bearing
The minifier removes /* … */ unconditionally, including inside /* … */ blocks that were never comments to begin with:
/* a > b */ .x { color: red }
minifies to .x{color:red} — correct. But two real uses of CSS comments are not documentation:
- License headers. Some icon and font licenses require the header ship with the CSS. Stripping comments strips the compliance notice.
- Source-map-free debugging markers and
/* stylelint-disable */directives. Stylelint reads directives from comments; deleting them changes what your linter reports the next time someone edits the file./* autoprefixer region:end */was a real directive with real behaviour.
The regex also does not know about nested-looking content: a comment containing */ inside a string still ends the comment at the first */ it sees.
4. Why your round-trip test passes anyway
A common CI check is: minify the source, beautify the result, compare against beautifying the source. Here is why that check can report agreement on broken output.
minify strips whitespace adjacent to ; } : , — including whitespace a beautify step just inserted inside a string. So minify re-glues precisely the characters beautify separated. Run the cycle on the content: "a; b" case and both branches converge on the same corrupted text, because both tools are regex over punctuation and neither tracks string state. A round-trip test proves two tools agree, not that either is correct. The only test that catches this class is comparing the parsed value of specific declarations — getComputedStyle or a real parser's AST — against expected strings.
5. What a minifier must not do, even though many do
- Merge duplicate selectors. With equal specificity the last declaration wins, so
.a{color:red}+.a{color:blue}is blue; a merged.a{color:blue}looks the same but reordering across other rules can change which one is last. - Drop
!important. It is a specificity statement, not noise. - Shorten
0.5sto.5sis safe; shorten0pxto0inside acalc()where units are required is not —calc(100% - 0)is invalid in some engines' parsers. - Remove the space in
1fr 1frgrids or insidecalc(100% - 2rem):-and+incalcrequire surrounding whitespace by spec, and a minifier that strips it produces invalid CSS that parses as one token. - Reorder or deduplicate
@importstatements — they must stay first in the file, and reordering changes which rules are overridden.
6. Deciding what to trust
Check the tool on these five inputs; a tool that survives all three tracks string state:
a { content: "a; b" }
.b { width: calc(100% - 2rem) }
.c { background: url("data:image/svg+xml;charset=utf8,<svg/>"); }
If it does not survive them, use a real parser: Lightning CSS, esbuild, or cssnano with postcss-value-parser. On the maintenance axis, cssnano's own README points at Lightning CSS for speed; the numbers and the release cadence behind that trade-off are on libraries and trends.
This site's tools are whitespace-and-comment tools with a known string-state blind spot: about states it, and the two failure inputs above are worth pasting into the beautifier yourself rather than trusting this page.