CSS::Minifier
CSS minifier for Raku - parses, optimizes, and re-serializes CSS stylesheets.
Features
- Plugin pipeline - modular optimization passes (values, colors, dedup, merging)
- Two levels - level 1 (safe normalizations) vs level 2 (structural optimizations)
- Color optimization - shorten hex colors, optionally convert to named colors (delegated to CSS::Writer/CSS::Properties)
- Value normalization -
bold → 700, normal → 400 - Duplicate removal - identical rulesets and
@font-face blocks deduplicated - Ruleset merging - same-selector rules merged, same-declaration selectors combined
- Shorthand consolidation - leverages CSS::Properties optimizer for compact output
- License preservation -
/*! */ comments kept with --preserve-licenses - CLI tool -
cssminify with stdin/file input and output redirection
Dependencies
Installation
zef install CSS::Minifier
Installing from source
cd /path/to/CSS-Minifier
zef install .
Requires Raku 6.d or later.
Usage
Command Line
# Read from file
cssminify input.css > output.css
# Level 2 (structural optimizations: dedup, merging)
cssminify -l2 input.css > output.css
# Write to file
cssminify -o output.css input.css
# Read from stdin
cat input.css | cssminify
# Preserve license comments
cssminify -p input.css
# Disable hex color shortening (keep #FF0000 instead of #F00)
cssminify --no-color-masks input.css
# Disable unknown-property preservation (declarations dropped by CSS::Properties stay dropped)
cssminify --no-preserve-unknown input.css
# Separate rules with newlines (readable output)
cssminify -r input.css
# Convert hex colors to named colors
cssminify -n input.css
# Verbose output (log plugin names)
cssminify -v input.css
# Print version
cssminify --version
Flags
| Short | Long | Description |
|---|
-o | --output | Write to file instead of stdout |
-l | --level | Optimization level: 1 (default) or 2 (structural) |
-p | --preserve-licenses | Keep /*! */ license comments |
-n | --color-names | Convert hex colors to named colors |
-m / -/m | --color-masks / --no-color-masks | Enable/disable hex color shortening |
-u / -/u | --preserve-unknown / --no-preserve-unknown | Enable/disable unknown-property preservation (default: enabled) |
-r | --readable | Separate rules with newlines |
-v | --verbose | Log plugin names to stderr |
| --version | Print version and exit |
Negatable booleans accept --no-flag (long) or -/f (short), e.g. --no-color-masks or -/m.
Short flags with values use = or fused syntax: -l=2 or -l2 (not -l 2).
Library
use CSS::Minifier;
# Level 1 - safe normalizations
my $min = CSS::Minifier.minify($css);
# Level 2 - structural optimizations (dedup, merging)
my $min = CSS::Minifier.minify($css, :level(2));
# Preserve license comments
my $min = CSS::Minifier.minify($css, :preserve-licenses);
# Convert hex colors to named colors
my $min = CSS::Minifier.minify($css, :color-names);
# Disable hex color shortening
my $min = CSS::Minifier.minify($css, :!color-masks);
# Disable unknown-property preservation (dropped by CSS::Properties)
my $min = CSS::Minifier.minify($css, :!preserve-unknown);
# Add custom plugins (runs after all level plugins, in append order)
# Custom plugins must implement the CSS::Minifier::Plugin role.
my $min = CSS::Minifier.minify($css, :level(2), :extra-plugins[$my-plugin]);
Optimization Levels
Level 1 (default)
- Font-weight normalization (
bold → 700, normal → 400) - Color shortening (
#FF0000 → #F00, red → #F00) - Shorthand consolidation (via CSS::Properties optimizer)
- Comment removal (
/*! */ kept with --preserve-licenses) - Whitespace removal (via compact writer)
Level 2
- Duplicate ruleset removal
@font-face deduplication- Same-selector ruleset merging
- Same-declaration selector combination
Note: at-rules (@keyframes, @supports, @layer) are preserved
with all their declarations intact via a pre-parse scan, but are not
subject to deduplication or value normalization.
Examples
h1 { color: red; }
h2 { color: red; }
h1 { margin: 0; }
Level 1 Output
h1{color:#F00}h2{color:#F00}h1{margin:0}
Level 2 Output
h1, h2{color:#F00}h1{margin:0}
Limitations
Warning: The merging plugin can silently change cascade order. Review
level-2 output before deploying to production.
- Non-adjacent same-declaration merging - rulesets with identical
declarations are merged even when propertyless rules separate them,
potentially changing computed styles.
@keyframes / @supports / @container / @layer - these at-rules are not
processed by this minifier's pipeline (dedup, merging, value normalization).
All declarations inside them are preserved via a pre-parse scan
(both known and unknown properties), but values come through un-minified
since they bypass the standard pipeline. Only @media and @font-face
are structurally handled.- Propertyless rules - rulesets without properties (parsing artifacts)
are silently dropped during dedup and merging. Same-declaration merging
skips them rather than treating them as barriers, which can merge
rulesets that are not strictly adjacent.
- Unknown properties - CSS::Properties drops properties it doesn't recognize
(e.g.
text-decoration-line, outline-offset). CSS::Minifier
works around this by re-injecting missing declarations after minification
(enabled by default; disable with --no-preserve-unknown). Declarations
inside at-rules (@media, @supports, etc.) are also preserved. Known
properties inside at-rules that CSS::Stylesheet drops (@keyframes,
@supports, @container, @layer) are also preserved via the
pre-parse scan, though they come through without value normalization. - Comments - CSS::Stylesheet strips all comments during parsing.
The
--preserve-licenses flag extracts /*! */ comments from the raw
CSS via regex before parsing, then prepends them to the output.
A known limitation: the pattern may match inside string values
(e.g. content: "...").
AUTHOR
Sasha Abbott sashaa@disroot.org
LICENSE
This library is free software; you can redistribute it and/or modify it under CC0.