CSS Deduplication and File Size: What’s Left After Compression
Published on Nov 12, 2026, filed under development, css, performance, maintainability, optimization. (Share this post, e.g., on Mastodon.)
CSS Dedup (source) consolidates duplicate CSS declarations, following the idea of using declarations just once. As a maintainability and performance optimization technique, consolidations change how many bytes a style sheet has. How much is saved though—and does any of it survive Gzip and Brotli? Also, where should deduplication happen: on source files, before minification, or after?
For more hard data, I ran CSS Dedup over the style sheets of the 124 websites in the minifier benchmarks sample set.
Contents
Method
- Fetched each of the 124 benchmark sites’ homepages on November 11, 2026, and collected all linked style sheets plus inline
styleblocks (no@imports followed): 2,264 style sheets, 1,899 of them unique (shared libraries counted once). - 1 site was unavailable and 17 style sheets failed to parse (responses that weren’t CSS, plus some broken style sheets), leaving 1,882 style sheets from 123 sites, with 58.3 MB of CSS in total.
- Each style sheet was processed individually through CSS Dedup 1.13.3 (
--fix, with--savings-onlyand--aggressiveas noted) and Lightning CSS 1.33.0 (minify, default targets). - Compression: Gzip at level 9, Brotli at quality 11.
Results
Totals across all 1,882 style sheets, with changes relative to the original (top) or minified (bottom) style sheets:
| Pipeline | Raw (KB) | Gzip (KB) | Brotli (KB) |
|---|---|---|---|
| Original | 58,312 | 8,418 | 6,097 |
Dedup (-f) | 65,397 (+12.15%) | 8,932 (+6.11%) | 6,446 (+5.74%) |
Dedup (-f -s) | 57,573 (−1.27%) | 8,412 (−0.07%) | 6,103 (+0.11%) |
Dedup (-f -a -s) | 57,106 (−2.07%) | 8,404 (−0.17%) | 6,098 (+0.02%) |
| Minified | 54,281 | 7,989 | 5,791 |
Dedup (-f -s) → minify | 53,748 (−0.98%) | 7,989 (±0.00%) | 5,799 (+0.13%) |
Dedup (-f -a -s) → minify | 53,335 (−1.74%) | 7,981 (−0.10%) | 5,794 (+0.04%) |
Minify → dedup (-f) | 61,600 (+13.48%) | 8,505 (+6.46%) | 6,143 (+6.06%) |
Minify → dedup (-f -s) | 53,754 (−0.97%) | 7,988 (−0.01%) | 5,798 (+0.11%) |
Minify → dedup (-f -a -s) | 53,353 (−1.71%) | 7,982 (−0.09%) | 5,795 (+0.06%) |
(-f: --fix, -a: --aggressive, -s: --savings-only.)
Per site:
| Pipeline | Median Raw | Median Gzip | Median Brotli | Best Raw |
|---|---|---|---|---|
Dedup (-f -s) | −0.88% | −0.06% | ±0.00% | −12.41% |
Dedup (-f -a -s) | −1.64% | −0.15% | −0.04% | −14.53% |
Minify → dedup (-f -s) | −0.50% | −0.04% | +0.02% | −12.89% |
Minify → dedup (-f -a -s) | −1.12% | −0.10% | −0.03% | −14.13% |
Observations
Raw savings are modest, and compression may erase them. With --savings-only, deduplication saves about 1% of raw bytes (2% with --aggressive), but Gzip and Brotli keep almost none of it. The site with the biggest savings in absolute terms shed 63 KB (13%) from its minified CSS—but less than 1 KB after Brotli. Of the minified style sheets that --savings-only changed, 45% were actually bigger after Brotli than before.
This is explicable: A repeated declaration like color:#fff is already cheap in compressed form, encoded as a short back-reference to its earlier occurrence. Consolidation removes these cheap repeats but adds selector text that is new and less repetitive, and the reordering can break up longer matches. (As noted in previous articles and in the CSS Dedup docs, with declaration deduplication, both maintainability and performance improvements depend a lot on the selectors.)
Order barely matters—as long as nothing in between generates CSS. With Lightning CSS’s default targets, which lower no syntax, deduplicating before minification and after it produced byte-for-byte the same size for 87% of style sheets, and totals within 0.02% of each other. Running the minifier once more after a late deduplication gained another 0.05%.
Without --savings-only, built CSS may grow. Plain --fix made 815 of the 1,085 style sheets it changed bigger, by 12–13% in total (6% compressed). Framework and generated CSS repeats declarations across long, unrelated selectors, and folding those into shared selector lists costs more than it saves. This is consistent with CSS Dedup’s design—it prioritizes using declarations once over byte counts—but it supports that --fix on its own is best only used to optimize built CSS if selectors are short.
What the data doesn’t cover: These are style sheets as shipped, mostly built and often minified. Hand-authored source CSS may behave differently, as could different compression settings (say, Brotli at a lower, on-the-fly quality level), and build steps that lower modern syntax for older browsers (see below).
On Technique and Tooling
First, to properly assess UDJO and CSS Dedup, it’s important to understand:
UDJO requires understanding of the code to tell where maintainability benefits really lie. No tool can do this (so far), and therefore, on the maintainability side, CSS Dedup is blunt—the deduplication it achieves does not mean you can just blindly update any declaration value later.
CSS Dedup is to be seen as an assistant. It will be improved and may eventually be less blunt when it comes to improving maintainability, but it isn’t yet a substitute for writing highly maintainable CSS.
The effectiveness of both technique (UDJO) and tool (CSS Dedup) depend on the code itself. Small projects with effective use of custom properties may already be highly maintainable; the performance of large but well-compressed sites with a lot of long selectors may not benefit from declaration deduplication as shown; yet sites with repetition of similar-purpose declarations and relatively short selectors may still benefit both maintainability-wise and performance-wise. (I believe that an even larger sample would show this.)
Assessment
What the data indicates is that for transfer size, CSS deduplication may be negligible whenever responses are compressed (CSS Dedup could be used to check). What remains is the uncompressed size—what browsers need to parse and keep in memory—at around 1%.
That suggests the following recommendations for where to run it, which CSS Dedup now points out, too:
For maintainability, run CSS Dedup on source files. That’s where using declarations once pays off, because that’s the code being maintained. Report mode works as a CI check, and
--fixcleans up. It’s also the only placement that changes the files you edit—the PostCSS plugin, for example, only changes the build output. However, for best maintainability results, there’s still a need to review and tweak.For size, use
--savings-only, and pick the placement based on source maps. In the build before minification (the PostCSS plugin withfixandsavingsOnly) and after minification (css-dedup -f -son the minified files) perform the same, except when a step that lowers syntax sits in between (see below). The PostCSS route keeps source maps correct, while the late route makes them stale—so if you ship or rely on source maps, deduplicate before minifying. If you don’t, a final pass over minified files is simple and lets--savings-onlymeasure the bytes that actually ship.Treat
--aggressiveas an option, not a default. It doubles raw savings, but those savings still disappear under compression, so the slightly higher risk (given that aggressive mode moves from provably to probably safe changes) may not be worth it for size alone.
There’s one case where deduplication pays off even after compression: when the build itself generates duplicate declarations. On this site, for example, Lightning CSS lowers light-dark() for the configured browser targets (iOS 16 and later, plus browsers with more than 0.5% usage), which grows the main style sheet from 8.9 KB to 11.2 KB when minified. A --savings-only pass after that removes 1.5 KB (−13.1%)—and still 2.0% with Gzip and 2.3% with Brotli. Only a pass that runs after the lowering step sees this duplication, which makes the end of the pipeline a good default for size: It catches whatever the toolchain adds, and when there’s nothing to catch, it costs nothing (which is why I take this approach).
I believe this is useful data to assess CSS repetition, compression, and deduplication as an optimization vector. Personally, it has been instructive to run through this; while CSS Dedup is a part of my setup that I consider helpful (probably because I’ve manually deduplicated style sheets for years), the analysis made some of its its limitations clearer.
The insight to take away here, at least the one I suggest to remember, is that UDJO and CSS Dedup require informed use. They are not effective in every project—but, to answer the question I raised, they are effective in some.
If you’re a CSS optimizer, follow the work on CSS Dedup, like using the insights from this analysis to make it compression-aware!
About Me
I’m Jens (long: Jens Oliver Meiert), and I’m an engineering lead, guerrilla philosopher, and indie publisher. I’ve worked as a technical lead and manager at various companies (e.g., Google); I’m an active web and tool developer (code optimization, digital defense), a contributor to web standards (like HTML, CSS, WCAG), and a book author (O’Reilly, dxsrc). You’ll like my work if you value principled, pragmatic problem-solving. Let’s connect.
