From csscompressor¶
csscompressor is a pure-Python port of the CSS half of the YUI Compressor.
It is a value-rewriting minifier, not a whitespace-only stripper: it collapses whitespace, drops comments, and rewrites
values – colors to their shortest form, redundant zeros and units removed – through a sequence of regular-expression
passes. Its surface is one function, csscompressor.compress(css), plus compress_partitioned for splitting output
under IE’s 4095-selector limit. It has no runtime dependencies and is used as a drop-in CSS compressor in Python build
pipelines that want YUI-equivalent output without a Java or Node step.
turbohtml covers that ground with turbohtml.clean.minify_css(), the same value-rewriting minifier class
implemented in C. It reaches a smaller result on real stylesheets, keeps custom-property values and string contents
byte-exact, and runs in linear time where csscompressor’s regex passes degrade on large input.
turbohtml vs csscompressor¶
Dimension |
turbohtml |
csscompressor |
|---|---|---|
Scope |
Value-safe CSS minifier ( |
Value-rewriting CSS compressor ( |
Feature breadth |
Whitespace/comment removal, color and number shortening, constant |
Whitespace/comment removal, color and number shortening, line wrapping, output partitioning |
Performance |
Native C, linear time (40x-155x faster on the corpus below) |
Pure-Python regex passes, degrade on large stylesheets |
Typing |
Typed public API ( |
Untyped |
Dependencies |
None (ships the C extension) |
None (pure Python) |
Maintenance |
Actively developed alongside the turbohtml serializer |
Maintained, stable, YUI-scoped |
Feature overlap¶
The compression path ports 1:1:
Minify a full stylesheet:
csscompressor.compress(css)maps toturbohtml.clean.minify_css(css).Both shorten colors to their shortest equivalent (
#ffffffto#fff,rgb(255,0,0)tored), drop redundant leading and trailing zeros, and remove units on zero lengths.Both strip comments and collapse insignificant whitespace between tokens.
Both keep
/*! ... */bang comments (license or copyright banners) verbatim. turbohtml always preserves them; csscompressor preserves them by default (preserve_exclamation_comments=True).
What turbohtml adds¶
Constant
calc()folding:calc(2px + 3px)becomes5px. csscompressor leaves the expression intact.Box-longhand-to-shorthand merging (
margin,padding, and friends) and merging of adjacent rules with equal bodies. csscompressor does neither, so the size gap widens on framework CSS that leans on those forms.Byte-exact custom-property values. turbohtml treats a
--varvalue as the literal token streamvar()splices verbatim (CSS Variables 1 §2); csscompressor rewrites the whitespace inside it, so its output is not guaranteed to parse to the same cascade.Opt-in Baseline-year shorthands via
CSSMinify:CSSMinify(baseline=2021)additionally mergesinset, the flexgap, and two-valueoverflowonce they reached Baseline.Inline
style-attribute minification viaminify_css_inline()for bare declaration lists.A typed surface:
minify_css()and the frozenCSSMinifyoptions object.A native-C pipeline that stays linear where csscompressor’s regex passes turn quadratic on large input.
What csscompressor has that turbohtml does not¶
max_linelen: csscompressor can wrap the output every N columns. turbohtml emits a single line, which is the right shape once the bytes are gzipped on the wire. No equivalent, and none needed for network transfer.compress_partitioned: csscompressor can split the output into chunks under IE’s 4095-selector-per-file limit. turbohtml has no equivalent; split the source into separate stylesheets before minifying if you still target that limit.Dropping bang comments: csscompressor’s
preserve_exclamation_comments=Falseremoves/*! ... */banners. turbohtml always keeps them; strip the banner from the source before minifying if you need it gone.
Performance¶
turbohtml’s output is smaller on every framework, including the custom-property-heavy bulma.css, and its C engine is
40x to 155x faster – csscompressor’s regex passes turn quadratic on a large stylesheet, where turbohtml stays linear.
csscompressor also rewrites whitespace inside custom-property values, which CSS Variables 1 §2 keeps as the literal token stream that var() splices
verbatim, so its output is not guaranteed to parse to the same cascade. Each ratio is against turbohtml:
stylesheet |
turbohtml |
|||
|---|---|---|---|---|
size |
time |
size |
time |
|
normalize.css (6 kB) |
1.7 kB |
88.6 µs |
1.8 kB (1.07x) |
1.11 ms (12.6x) |
pico.css (90 kB) |
80.8 kB |
1.46 ms |
81.6 kB (1.01x) |
35.5 ms (24.3x) |
animate.css (93 kB) |
72.8 kB |
684 µs |
75.7 kB (1.04x) |
25 ms (36.6x) |
foundation.css (164 kB) |
130.6 kB |
2.24 ms |
136.4 kB (1.04x) |
59.7 ms (26.7x) |
bootstrap.css (274 kB) |
229.1 kB |
6.62 ms |
234.2 kB (1.02x) |
81.9 ms (12.4x) |
bulma.css (745 kB) |
680.7 kB |
19.1 ms |
681.3 kB (1.001x) |
580 ms (30.4x) |
turbohtml also folds constant calc(), merges box longhands into shorthands, and combines adjacent equal-bodied
rules, none of which csscompressor attempts, so the size gap widens on framework CSS that leans on those forms.
How to migrate¶
The import and the call name are the only change:
# csscompressor
from csscompressor import compress
# turbohtml
from turbohtml.clean import minify_css
csscompressor |
turbohtml |
|---|---|
|
|
|
|
|
no equivalent (single-line output) |
|
no equivalent (split the source before minifying) |
from turbohtml.clean import minify_css
print(minify_css("a{ color: rgb(255, 0, 0); width: calc(2px + 3px) }"))
a{color:red;width:5px}
Gotchas and pitfalls¶
turbohtml takes no per-call flags.
compress’smax_linelenandpreserve_exclamation_commentsarguments have no counterpart; every rewrite turbohtml applies is value-safe, and the only knob is the frozenCSSMinifybaselineyear.Custom-property values differ. csscompressor collapses whitespace inside a
--varvalue; turbohtml keeps it byte-exact. Output that fed avar()splice can change under csscompressor but not turbohtml, so byte-comparing the two minifiers’ results on custom-property-heavy CSS will show a difference by design.Inline declarations need the inline entry point. A bare
color:red;margin:0from astyleattribute has no selector or braces; pass it tominify_css_inline(), notminify_css().Output size shifts. turbohtml folds
calc(), merges shorthands, and combines equal-bodied rules, so its output is smaller than csscompressor’s rather than byte-identical; pin tests to turbohtml’s output, not to a stored csscompressor string.