CSSTidy CSS Formatter

Is CSS Minification Safe? Four Places Whitespace Is Content

CSSTidy — CSS Formatter & Minifier Guides · Updated 2026-10-12 · All guides

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.5s to .5s is safe; shorten 0px to 0 inside a calc() where units are required is not — calc(100% - 0) is invalid in some engines' parsers.
  • Remove the space in 1fr 1fr grids or inside calc(100% - 2rem): - and + in calc require surrounding whitespace by spec, and a minifier that strips it produces invalid CSS that parses as one token.
  • Reorder or deduplicate @import statements — 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.

Developer Sponsor / Partner
Copied to clipboard!