Format, minify, and convert between CSS and SCSS.
How the cascade resolves an (A,B,C) tuple, which compression transforms are safe, and which Sass constructs have no native counterpart.
CSS Cascade Level 5 computes specificity as three independent counters: A counts ID selectors, B counts classes, attribute selectors and pseudo-classes, and C counts element types and pseudo-elements. `#nav .item > a:hover` scores (1,2,1): one ID, one class plus one pseudo-class, and one type. Comparison is lexicographic, so (1,0,0) beats (0,10,0) no matter how many classes pile up. `:where()` always contributes (0,0,0), even when it wraps an ID selector, while `:is()` takes the specificity of its highest argument. An inline `style` attribute is not part of this count at all: it sits in a higher tier of the cascade.
A safe minifier strips whitespace, newlines and comments, drops the semicolon before `}`, trims leading zeros (`0.5em` becomes `.5em`), removes units from zero lengths (`margin: 0px` becomes `margin: 0`) and folds six-digit hex colors into three when the pairs repeat (`#ffffff` becomes `#fff`). What it cannot do safely is reorder colliding declarations, merge longhand properties into a shorthand when any of them uses `var()` (the value is unknown until runtime), or delete `/*! ... */` comments, which are reserved for license headers. Once the response is served with gzip or Brotli, the extra saving usually lands between 3% and 8%.
Native nesting, custom properties and cascade layers now cover almost everything Sass was used for, but the differences matter. `$color: red` is a compile-time substitution that disappears from the output, whereas `--color: red` lives in the CSSOM, inherits down the tree, can be read with `getComputedStyle()` and reassigned from JavaScript. Functions, `@mixin`, `@extend` and `@each` loops have no native counterpart. A custom property also cannot drive a media query condition: `@media (width > var(--bp))` is invalid. Declaring `@layer base, components;` pins priority per layer, so a low-specificity component rule no longer depends on import order.
`!important` is not an absolute trump card. When two declarations from the same origin are both important, the higher specificity wins and, on a tie, the later one does. A running animation also overrides any important declaration while its keyframes play, and important declarations from user and user-agent stylesheets outrank important author declarations.
They are resolved to literal values and vanish from the output. If you need runtime theming, rewrite them as custom properties: `--brand: #0af` on `:root` and `color: var(--brand, #08c)` at the usage site, where the second argument is the fallback applied when the variable is not set.
Less than you would expect. Minification cuts the raw file by roughly 15% to 25%, but gzip and Brotli already compress repeated whitespace very efficiently, so the extra saving on the compressed response is around 3-8%. The real render-time win comes from removing unused rules and splitting critical CSS from deferred CSS.