From lightningcss¶
lightningcss binds the Rust CSS engine behind Parcel to Python through
process_stylesheet. It is a cascade-aware optimizer, not just a minifier: alongside whitespace and value compaction
it drops declarations overridden elsewhere in the sheet, merges rules, adds or strips vendor prefixes, and rewrites
syntax down to a configured browser-target set, so it can reach a smaller result than a value-safe minifier can. That
target-driven approach makes it the CSS transform stage in Parcel and a common build-time optimizer for web bundles.
turbohtml covers the same ground with turbohtml.clean.minify_css(), a value-safe minifier. It applies only
transforms that hold on any conformant browser, so its default output needs no target list, parses to the same cascade
everywhere, minifies faster, and recovers from malformed input that lightningcss rejects. The
CSSMinify baseline year opts into newer-syntax shorthand merges when you are ready to
require them.
turbohtml vs lightningcss¶
Dimension |
turbohtml |
lightningcss |
|---|---|---|
Scope |
Value-safe CSS minify (full sheet and inline declarations) |
Cascade-aware CSS optimizer: minify, prefix, bundle, CSS modules |
Feature breadth |
Whitespace + value compaction, shortest colors, unit/number trimming, constant |
All of that plus cross-sheet dead-declaration removal, target-driven syntax rewriting, vendor prefixing,
|
Performance |
2-3x faster minify on the shared corpus (see Performance) |
Smaller output on most inputs by trading target configuration for size |
Typing |
Fully typed, frozen |
Typed bindings over the Rust engine |
Dependencies |
Native C extension in turbohtml, no extra dependency |
Native Rust extension |
Maintenance |
Maintained within turbohtml |
Tracks the Parcel/lightningcss Rust project |
Feature overlap¶
The minify surface ports 1:1:
lightningcss.process_stylesheet(css, minify=True)->turbohtml.clean.minify_css().Whitespace collapse, shortest hex/color forms, redundant unit and leading-zero trimming, and constant
calc()folding are applied by both.Adjacent-rule and shorthand merging: turbohtml merges the value-safe cases by default and the newer-syntax cases (
inset, flexgap, two-valueoverflow) when you setbaseline.
What turbohtml adds¶
Value-safe by construction: every transform round-trips to the same cascade on any conformant browser, so there is no target list to configure and no way to emit syntax a target cannot parse.
WHATWG error recovery: turbohtml minifies malformed stylesheets that lightningcss’s parser rejects, for example a media query in
foundation.cssthat the WHATWG rules accept.Faster runs: 2-3x quicker minify on the shared corpus.
Inline-declaration minify via
turbohtml.clean.minify_css_inline()for barestyle-attribute declaration lists, without a surrounding selector or braces.Custom-property values and string contents stay byte-exact, as CSS Variables 1 requires.
What lightningcss has that turbohtml does not¶
Cross-sheet cascade optimization: lightningcss removes declarations overridden elsewhere in the sheet. turbohtml does not, because the result depends on which browsers you support; there is no value-safe equivalent.
Target-driven syntax rewriting to a browser-target set. turbohtml’s
baselinegates newer-syntax shorthand merges but does not rewrite down to an arbitrary older-target set.Vendor prefixing (adding or removing prefixes for a target). No equivalent; turbohtml preserves the input’s prefixes.
@importbundling and CSS-modules transforms. No equivalent; turbohtml minifies a single stylesheet in place.
Performance¶
lightningcss produces the smaller output on most of the corpus – up to five percent under turbohtml – because it
optimizes for a browser-target set: it removes declarations overridden across the sheet and emits syntax those targets
support. turbohtml applies only transforms that hold on any conformant browser, so its default output needs no target
list and parses to the same cascade everywhere; the CSSMinify baseline year opts into the
newer-syntax shorthand merges when you are ready to require them. turbohtml also minifies two to three times faster,
comes out ahead on normalize.css, and recovers from malformed CSS that lightningcss rejects: foundation.css
raises a parse error on a media query the WHATWG rules accept, where turbohtml minifies all six stylesheets. 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.02x) |
44.6 µs (0.6x) |
pico.css (90 kB) |
80.8 kB |
1.46 ms |
80.0 kB (0.99x) |
1.43 ms (1.0x) |
animate.css (93 kB) |
72.8 kB |
684 µs |
68.8 kB (0.95x) |
1.16 ms (1.8x) |
bootstrap.css (274 kB) |
229.1 kB |
6.62 ms |
228.7 kB (0.998x) |
4.14 ms (0.7x) |
bulma.css (745 kB) |
680.7 kB |
19.1 ms |
674.3 kB (0.99x) |
11.2 ms (0.6x) |
Reach for lightningcss when you can pin a browser-target set and want the last few percent of size; reach for turbohtml when you want value-safe output with no configuration, faster runs, and tolerance of real-world CSS.
How to migrate¶
The import and the call are the only change:
# lightningcss
from lightningcss import process_stylesheet
process_stylesheet(css, minify=True)
# turbohtml
from turbohtml.clean import minify_css
minify_css(css)
lightningcss |
turbohtml |
|---|---|
|
|
|
|
No equivalent (full-sheet input only) |
|
from turbohtml.clean import minify_css
print(minify_css("a {\n color: #ffffff;\n margin: 0px 0px;\n}"))
a{color:#fff;margin:0}
To target a newer browser baseline, pass CSSMinify; the year gates the newer-syntax merges,
much as lightningcss’s targets gate its own:
from turbohtml.clean import CSSMinify, minify_css
print(minify_css("a{top:0;right:0;bottom:0;left:0}", CSSMinify(baseline=2021)))
a{inset:0}
Gotchas and pitfalls¶
lightningcss removes declarations overridden elsewhere in the sheet and rewrites syntax for its targets; turbohtml does neither by default, because both depend on which browsers you support. Set
baselineto recover the newer-syntax merges, but the whole-sheet cascade optimization has no value-safe equivalent.lightningcss aborts on a stylesheet its parser rejects; turbohtml follows the WHATWG error-recovery rules, so it minifies inputs like
foundation.cssthat lightningcss will not parse.lightningcss can add or drop vendor prefixes for a target; turbohtml preserves the input’s prefixes as written.
turbohtml keeps custom-property values and string contents byte-exact; do not expect the internal whitespace of a
var()value or a string literal to be collapsed.Both are native extensions (Rust versus C), so neither offers a pure-Python fallback.