From rcssmin

rcssmin latest releasercssmin supported Pythonsrcssmin licensercssmin monthly downloadsrcssmin total downloadsrcssmin GitHub starsrcssmin last commit

rcssmin is the most-used CSS minifier on PyPI, a fast C extension (with a pure-Python fallback) that is deliberately non-destructive. Its whole surface is one function, rcssmin.cssmin(style, keep_bang_comments=False): it strips comments, collapses insignificant whitespace, and rewrites nothing else, so #ffffff and 0px survive untouched. That verbatim-value guarantee is the point – build pipelines reach for rcssmin when they want the bytes smaller without any value being touched, and its speed comes from doing strictly less work. It has no runtime dependencies.

turbohtml covers that ground with turbohtml.clean.minify_css(), a value-rewriting minifier implemented in C. It does everything rcssmin does – comment stripping and whitespace collapsing – and then applies every rewrite that is provably value-safe, so the result is smaller while still parsing to the same cascade.

turbohtml vs rcssmin

Dimension

turbohtml

rcssmin

Scope

Value-safe CSS minifier (minify_css), plus inline style-attribute minification

Non-destructive whitespace/comment stripper (cssmin)

Feature breadth

Whitespace/comment removal, color and number shortening, constant calc() folding, box-longhand-to-shorthand merging, adjacent equal-body rule merging, optional Baseline-year shorthands

Whitespace/comment removal only; values left verbatim

Performance

Native C, linear time; smaller output on every framework in the corpus below

Native C, linear time; faster because it rewrites nothing

Typing

Typed public API (minify_css(), CSSMinify)

Untyped

Dependencies

None (ships the C extension)

None (C extension with pure-Python fallback)

Maintenance

Actively developed alongside the turbohtml serializer

Maintained, stable, deliberately fixed scope

Feature overlap

The comment-and-whitespace path ports 1:1:

  • Minify a full stylesheet: rcssmin.cssmin(css) maps to turbohtml.clean.minify_css(css).

  • Both strip comments and collapse insignificant whitespace between tokens.

  • Both keep /*! ... */ bang comments (license or copyright banners). turbohtml always preserves them; rcssmin preserves them when called with keep_bang_comments=True.

  • Both are idempotent and round-trip safe: the output parses to the same cascade as the input, and minifying it again is a no-op.

What turbohtml adds

rcssmin rewrites no values, so everything below is turbohtml-only:

  • Color shortening: #ffffff to #fff, rgb(255,0,0) to red. rcssmin leaves colors verbatim.

  • Number and unit shortening: redundant leading and trailing zeros dropped, units removed on zero lengths (0px to 0). rcssmin leaves them.

  • Constant calc() folding: calc(2px + 3px) becomes 5px. rcssmin leaves the expression intact.

  • Box-longhand-to-shorthand merging (margin, padding, and friends) and merging of adjacent rules with equal bodies. rcssmin does neither, so the size gap widens on framework CSS that leans on those forms.

  • Opt-in Baseline-year shorthands via CSSMinify: CSSMinify(baseline=2021) additionally merges inset, the flex gap, and two-value overflow once they reached Baseline.

  • Inline style-attribute minification via minify_css_inline() for bare declaration lists.

  • A typed surface: minify_css() and the frozen CSSMinify options object.

What rcssmin has that turbohtml does not

  • Verbatim value preservation. rcssmin’s non-destructive contract guarantees every value survives byte-for-byte (#ffffff stays #ffffff). If a downstream step needs the original literals unchanged, that guarantee has no turbohtml equivalent: turbohtml rewrites to the shortest value-safe form, so the cascade is identical but the bytes are not.

  • Dropping bang comments. rcssmin’s default keep_bang_comments=False removes /*! ... */ banners; passing True keeps them. turbohtml always keeps them, so there is no way to strip a banner through the minifier – remove it from the source before minifying.

  • Bytes input. rcssmin.cssmin accepts and returns bytes as well as str. turbohtml’s minify_css() takes str; decode first if your source is bytes.

  • Raw speed. rcssmin only strips whitespace, so on cold input it is faster; reach for it when a larger result is acceptable and speed matters more than size.

Performance

turbohtml’s output is smaller on every framework except the custom-property-heavy bulma.css, where rcssmin ends 0.1% ahead only by rewriting whitespace inside custom-property values. That rewrite is not value-safe: CSS Variables 1 §2 keeps a custom property’s value as its literal token stream, var() splices it verbatim and getPropertyValue() reads it back byte-exact, so a collapsed space is observable wherever the value is substituted or compared. rcssmin’s whitespace-only pass is faster because it does strictly less work. Each ratio is against turbohtml:

stylesheet

turbohtml

rcssmin

size

time

size

time

normalize.css (6 kB)

1.7 kB

88.6 µs

1.8 kB (1.03x)

5.27 µs (0.1x)

pico.css (90 kB)

80.8 kB

1.46 ms

82.1 kB (1.02x)

201 µs (0.2x)

animate.css (93 kB)

72.8 kB

684 µs

75.7 kB (1.04x)

168 µs (0.3x)

foundation.css (164 kB)

130.6 kB

2.24 ms

136.7 kB (1.05x)

375 µs (0.2x)

bootstrap.css (274 kB)

229.1 kB

6.62 ms

233.2 kB (1.02x)

625 µs (0.1x)

bulma.css (745 kB)

680.7 kB

19.1 ms

680.0 kB (0.999x)

1.77 ms (0.1x)

Both round-trip safely – the output parses to the same cascade – and both are idempotent. turbohtml is still far faster than every other value-rewriting minifier, which are pure-Python and turn quadratic on a large stylesheet.

How to migrate

The import and the call name are the only change:

# rcssmin
from rcssmin import cssmin

# turbohtml
from turbohtml.clean import minify_css

rcssmin

turbohtml

from rcssmin import cssmin

from turbohtml.clean import minify_css

cssmin(css)

minify_css(css)

cssmin(css, keep_bang_comments=True)

minify_css(css) (bang comments always kept)

cssmin(css) on a style attribute value

minify_css_inline(css)

from turbohtml.clean import minify_css

print(minify_css("a {\n  color: #ffffff;\n  margin: 0px 0px;\n}"))
a{color:#fff;margin:0}

For the value of an HTML style attribute – a bare declaration list with no selector or braces – use turbohtml.clean.minify_css_inline() instead:

from turbohtml.clean import minify_css_inline

print(minify_css_inline("color: #ff0000 ; margin: 0.50px"))
color:red;margin:.5px

Gotchas and pitfalls

  • Output size shifts. rcssmin leaves values verbatim; turbohtml shortens colors and numbers, folds calc(), and merges shorthands and equal-bodied rules, so its output is smaller than rcssmin’s rather than byte-identical. Pin tests to turbohtml’s output, not to a stored rcssmin string.

  • turbohtml takes no per-call flags. rcssmin’s keep_bang_comments argument has no counterpart because turbohtml always keeps /*! ... */ license comments and always drops the rest; the only knob is the frozen CSSMinify baseline year, which bounds output syntax, never the cascade.

  • Inline declarations need the inline entry point. A bare color:red;margin:0 from a style attribute has no selector or braces; pass it to minify_css_inline(), not minify_css().

  • Custom-property values differ. rcssmin collapses whitespace inside a --var value; turbohtml keeps it byte-exact. Byte-comparing the two minifiers on custom-property-heavy CSS will show a difference by design.

  • Input type. rcssmin.cssmin accepts bytes; minify_css() takes str. Decode a bytes source before passing it.