What a minifier may delete without asking
Five things go, and only five. Comments, unless they start `/*!`, which is the convention for a license banner and is therefore kept by a switch that defaults to keeping it. Runs of whitespace are collapsed to one space and then dropped wherever a browser would not render them - next to a brace, a semicolon or a comma, at the start or end of the file, or with a block-level element on either side. A semicolon directly before a `}` is dropped, because the block was ending anyway. Inside a declaration value, `0px` becomes `0` for lengths only. And a six-digit color whose three pairs are identical becomes three digits.
Everything else is left exactly as written. No rule is merged, no property is reordered, no vendor prefix is added, `bold` is not turned into `700`, `margin: 4px 2px` is not shortened, and no color is converted to another notation. Those transformations need the grammar of every property and the cascade of the whole project, and a tool that only ever sees one file cannot have either. The output is deliberately of a kind you can diff against the input and understand.
The three places a careless minifier breaks a stylesheet
The first is a colon in a selector. `.card :hover` selects hovered descendants of `.card`; `.card:hover` selects the card itself. Both are valid, both are common, and one space is the entire difference - so this pass tightens a colon only inside a declaration block, where the property name has just ended. The same care applies to a media feature such as `(min-width: 700px)`, where either spelling is legal, so tightening that one is safe and is done.
The second is arithmetic. `calc(100% - 20px)` requires the spaces around the `-`, because `100% -20px` is a parse error rather than a subtraction. But `margin: 1px -2px` is two values, the second negative, and its space is just as load-bearing. The pass therefore keeps a space whenever a `+` or `-` is involved outside a function it has recognized as arithmetic (`calc`, `min`, `max`, `clamp` and their relatives), and preserves both sides inside one. Selectors are different again: `li + a` and `li+a` mean the same thing, so a sibling combinator really is tightened.
The third is a value the pass cannot interpret. A custom property holds whatever its author wrote - `--gap: 0px` may be substituted into a length, a time or a background list - so its value is copied through untouched, which also means a color or a zero inside it is left alone. Strings and `url(...)` are copied for the same reason: a `/*` inside a `content` string is not a comment, and `url(https://host/a/*b*/c.png)` is a real path. Only then can the counts above be trusted.
Which whitespace in HTML is actually rendered
HTML has one place where whitespace matters and one where it does not. Under the default `white-space: normal`, a run of whitespace collapses to a single space, and that space is kept when both of its neighbors are inline: two links on one line stay two links with a space between them. Beside a block-level element, at the start of a block or at the end of one, the whitespace is not rendered at all and goes - which is where almost all of the saving in a formatted page comes from, because that is all indentation.
Anything the pass cannot classify stays inline, which costs a byte and cannot change a layout. Four elements are never touched at all: `pre`, `textarea`, `script` and `style` are copied word for word, because their contents are text rather than markup - so a pasted page keeps its code block and its scripts exactly as they were. Comments go, except a license banner starting `<!--!` and a conditional comment `<!--[if ...]>`, which carries markup aimed at one browser. Tags are tidied from the inside: one space between attributes, no space around `=`, attribute values untouched, and the self-closing slash kept, because inside inline SVG that slash is what ends an element.
The honest limit is `white-space: pre-wrap`: an element styled that way does render its whitespace, and nothing in the text of a file says so. If the difference matters, wrap that content in `pre`, which this pass recognizes, or leave the page as it is.
Beautifying, and why the two directions round-trip
The other direction removes nothing at all. A stylesheet is laid out one declaration per line with indentation following the nesting, so an `@media` block reads as a block; a page is laid out one block element per line, with inline content left on the line it belongs to - `<p>Hello <b>world</b></p>` stays one line, because splitting inline content formats the source rather than the page. Comments are kept exactly where the author left them, on their own line if they had one. Attribute spacing is tidied the same way the minifier tidies it.
Because both directions use the same rule for deciding which whitespace exists, they compose: minifying a beautified file gives the same bytes as minifying the original, and beautifying twice gives the same result as beautifying once. Both properties are asserted rather than assumed. A file that does not balance - a `{` without its `}`, a string or a comment that never closes, a `<pre>` that is never closed - is refused with the line, the column and a caret under the trouble, rather than half-processed into something that looks finished.