clean-css is a fast and efficient CSS optimizer for Node.js platform and any modern browser.
According to tests it is one of the best available.
Table of Contents
Node.js version support
clean-css requires Node.js 10.0+ (tested on Linux, OS X, and Windows)
Install
npm install --save-dev clean-css
Use
var CleanCSS = require('clean-css');
var input = 'a{font-weight:bold;}';
var options = { };
var output = new CleanCSS(options).minify(input);
What's new in version 5.3
clean-css 5.3 introduces one new feature:
- variables can be optimized using level 1's
variableValueOptimizers
option, which accepts a list of value optimizers or a list of their names, e.g. variableValueOptimizers: ['color', 'fraction']
.
What's new in version 5.0
clean-css 5.0 introduced some breaking changes:
- Node.js 6.x and 8.x are officially no longer supported;
transform
callback in level-1 optimizations is removed in favor of new plugins interface;- changes default Internet Explorer compatibility from 10+ to >11, to revert the old default use
{ compatibility: 'ie10' }
flag; - changes default
rebase
option from true
to false
so URLs are not rebased by default. Please note that if you set rebaseTo
option it still counts as setting rebase: true
to preserve some of the backward compatibility.
And on the new features side of things:
- format options now accepts numerical values for all breaks, which will allow you to have more control over output formatting, e.g.
format: {breaks: {afterComment: 2}}
means clean-css will add two line breaks after each comment - a new
batch
option (defaults to false
) is added, when set to true
it will process all inputs, given either as an array or a hash, without concatenating them.
What's new in version 4.2
clean-css 4.2 introduces the following changes / features:
- Adds
process
method for compatibility with optimize-css-assets-webpack-plugin; - new
transition
property optimizer; - preserves any CSS content between
/* clean-css ignore:start */
and /* clean-css ignore:end */
comments; - allows filtering based on selector in
transform
callback, see example; - adds configurable line breaks via
format: { breakWith: 'lf' }
option.
What's new in version 4.1
clean-css 4.1 introduces the following changes / features:
inline: false
as an alias to inline: ['none']
;multiplePseudoMerging
compatibility flag controlling merging of rules with multiple pseudo classes / elements;removeEmpty
flag in level 1 optimizations controlling removal of rules and nested blocks;removeEmpty
flag in level 2 optimizations controlling removal of rules and nested blocks;compatibility: { selectors: { mergeLimit: <number> } }
flag in compatibility settings controlling maximum number of selectors in a single rule;minify
method improved signature accepting a list of hashes for a predictable traversal;selectorsSortingMethod
level 1 optimization allows false
or 'none'
for disabling selector sorting;fetch
option controlling a function for handling remote requests;- new
font
shorthand and font-*
longhand optimizers; - removal of
optimizeFont
flag in level 1 optimizations due to new font
shorthand optimizer; skipProperties
flag in level 2 optimizations controlling which properties won't be optimized;- new
animation
shorthand and animation-*
longhand optimizers; removeUnusedAtRules
level 2 optimization controlling removal of unused @counter-style
, @font-face
, @keyframes
, and @namespace
at rules;- the web interface gets an improved settings panel with "reset to defaults", instant option changes, and settings being persisted across sessions.
Important: 4.0 breaking changes
clean-css 4.0 introduces some breaking changes:
- API and CLI interfaces are split, so API stays in this repository while CLI moves to clean-css-cli;
root
, relativeTo
, and target
options are replaced by a single rebaseTo
option - this means that rebasing URLs and import inlining is much simpler but may not be (YMMV) as powerful as in 3.x;debug
option is gone as stats are always provided in output object under stats
property;roundingPrecision
is disabled by default;roundingPrecision
applies to all units now, not only px
as in 3.x;processImport
and processImportFrom
are merged into inline
option which defaults to local
. Remote @import
rules are NOT inlined by default anymore;- splits
inliner: { request: ..., timeout: ... }
option into inlineRequest
and inlineTimeout
options; - remote resources without a protocol, e.g.
//fonts.googleapis.com/css?family=Domine:700
, are not inlined anymore; - changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use
{ compatibility: 'ie9' }
flag; - renames
keepSpecialComments
to specialComments
; - moves
roundingPrecision
and specialComments
to level 1 optimizations options, see examples; - moves
mediaMerging
, restructuring
, semanticMerging
, and shorthandCompacting
to level 2 optimizations options, see examples below; - renames
shorthandCompacting
option to mergeIntoShorthands
; - level 1 optimizations are the new default, up to 3.x it was level 2;
keepBreaks
option is replaced with { format: 'keep-breaks' }
to ease transition;sourceMap
option has to be a boolean from now on - to specify an input source map pass it a 2nd argument to minify
method or via a hash instead;aggressiveMerging
option is removed as aggressive merging is replaced by smarter override merging.
Constructor options
clean-css constructor accepts a hash as a parameter with the following options available:
compatibility
- controls compatibility mode used; defaults to ie10+
; see compatibility modes for examples;fetch
- controls a function for handling remote requests; see fetch option for examples (since 4.1.0);format
- controls output CSS formatting; defaults to false
; see formatting options for examples;inline
- controls @import
inlining rules; defaults to 'local'
; see inlining options for examples;inlineRequest
- controls extra options for inlining remote @import
rules, can be any of HTTP(S) request options;inlineTimeout
- controls number of milliseconds after which inlining a remote @import
fails; defaults to 5000;level
- controls optimization level used; defaults to 1
; see optimization levels for examples;rebase
- controls URL rebasing; defaults to false
;rebaseTo
- controls a directory to which all URLs are rebased, most likely the directory under which the output file will live; defaults to the current directory;returnPromise
- controls whether minify
method returns a Promise object or not; defaults to false
; see promise interface for examples;sourceMap
- controls whether an output source map is built; defaults to false
;sourceMapInlineSources
- controls embedding sources inside a source map's sourcesContent
field; defaults to false.
Compatibility modes
There is a certain number of compatibility mode shortcuts, namely:
new CleanCSS({ compatibility: '*' })
(default) - Internet Explorer 10+ compatibility modenew CleanCSS({ compatibility: 'ie9' })
- Internet Explorer 9+ compatibility modenew CleanCSS({ compatibility: 'ie8' })
- Internet Explorer 8+ compatibility modenew CleanCSS({ compatibility: 'ie7' })
- Internet Explorer 7+ compatibility mode
Each of these modes is an alias to a fine grained configuration, with the following options available:
new CleanCSS({
compatibility: {
colors: {
hexAlpha: false,
opacity: true
},
properties: {
backgroundClipMerging: true,
backgroundOriginMerging: true,
backgroundSizeMerging: true,
colors: true,
ieBangHack: false,
ieFilters: false,
iePrefixHack: false,
ieSuffixHack: false,
merging: true,
shorterLengthUnits: false,
spaceAfterClosingBrace: true,
urlQuotes: true,
zeroUnits: true
},
selectors: {
adjacentSpace: false,
ie7Hack: true,
mergeablePseudoClasses: [':active', ...],
mergeablePseudoElements: ['::after', ...],
mergeLimit: 8191,
multiplePseudoMerging: true
},
units: {
ch: true,
in: true,
pc: true,
pt: true,
rem: true,
vh: true,
vm: true,
vmax: true,
vmin: true
}
}
})
You can also use a string when setting a compatibility mode, e.g.
new CleanCSS({
compatibility: 'ie9,-properties.merging'
})
Fetch option
The fetch
option accepts a function which handles remote resource fetching, e.g.
var request = require('request');
var source = '@import url(http://example.com/path/to/stylesheet.css);';
new CleanCSS({
fetch: function (uri, inlineRequest, inlineTimeout, callback) {
request(uri, function (error, response, body) {
if (error) {
callback(error, null);
} else if (response && response.statusCode != 200) {
callback(response.statusCode, null);
} else {
callback(null, body);
}
});
}
}).minify(source);
This option provides a convenient way of overriding the default fetching logic if it doesn't support a particular feature, say CONNECT proxies.
Unless given, the default loadRemoteResource logic is used.
Formatting options
By default output CSS is formatted without any whitespace unless a format
option is given.
First of all there are two shorthands:
new CleanCSS({
format: 'beautify'
})
and
new CleanCSS({
format: 'keep-breaks'
})
however format
option also accept a fine-grained set of options:
new CleanCSS({
format: {
breaks: {
afterAtRule: false,
afterBlockBegins: false,
afterBlockEnds: false,
afterComment: false,
afterProperty: false,
afterRuleBegins: false,
afterRuleEnds: false,
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: '\n',
indentBy: 0,
indentWith: 'space',
spaces: {
aroundSelectorRelation: false,
beforeBlockBegins: false,
beforeValue: false
},
wrapAt: false,
semicolonAfterLastProperty: false
}
})
Also since clean-css 5.0 you can use numerical values for all line breaks, which will repeat a line break that many times, e.g:
new CleanCSS({
format: {
breaks: {
afterAtRule: 2,
afterBlockBegins: 1,
afterBlockEnds: 2,
afterComment: 1,
afterProperty: 1,
afterRuleBegins: 1,
afterRuleEnds: 1,
beforeBlockEnds: 1,
betweenSelectors: 0
}
}
})
which will add nicer spacing between at rules and blocks.
Inlining options
inline
option whitelists which @import
rules will be processed, e.g.
new CleanCSS({
inline: ['local']
})
new CleanCSS({
inline: ['none']
})
new CleanCSS({
inline: false
})
new CleanCSS({
inline: ['all']
})
new CleanCSS({
inline: ['local', 'mydomain.example.com']
})
new CleanCSS({
inline: ['local', 'remote', '!fonts.googleapis.com']
})
Optimization levels
The level
option can be either 0
, 1
(default), or 2
, e.g.
new CleanCSS({
level: 2
})
or a fine-grained configuration given via a hash.
Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
Level 0 optimizations
Level 0 optimizations simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else.
Level 1 optimizations
Level 1 optimizations (default) operate on single properties only, e.g. can remove units when not required, turn rgb colors to a shorter hex representation, remove comments, etc
Here is a full list of available options:
new CleanCSS({
level: {
1: {
cleanupCharsets: true,
normalizeUrls: true,
optimizeBackground: true,
optimizeBorderRadius: true,
optimizeFilter: true,
optimizeFont: true,
optimizeFontWeight: true,
optimizeOutline: true,
removeEmpty: true,
removeNegativePaddings: true,
removeQuotes: true,
removeWhitespace: true,
replaceMultipleZeros: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: false,
selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
tidySelectors: true,
variableValueOptimizers: []
}
}
});
There is an all
shortcut for toggling all options at the same time, e.g.
new CleanCSS({
level: {
1: {
all: false,
tidySelectors: true
}
}
});
Level 2 optimizations
Level 2 optimizations operate at rules or multiple properties level, e.g. can remove duplicate rules, remove properties redefined further down a stylesheet, or restructure rules by moving them around.
Please note that if level 2 optimizations are turned on then, unless explicitely disabled, level 1 optimizations are applied as well.
Here is a full list of available options:
new CleanCSS({
level: {
2: {
mergeAdjacentRules: true,
mergeIntoShorthands: true,
mergeMedia: true,
mergeNonAdjacentRules: true,
mergeSemantically: false,
overrideProperties: true,
removeEmpty: true,
reduceNonAdjacentRules: true,
removeDuplicateFontRules: true,
removeDuplicateMediaBlocks: true,
removeDuplicateRules: true,
removeUnusedAtRules: false,
restructureRules: false,
skipProperties: []
}
}
});
There is an all
shortcut for toggling all options at the same time, e.g.
new CleanCSS({
level: {
2: {
all: false,
removeDuplicateRules: true
}
}
});
Plugins
In clean-css version 5 and above you can define plugins which run alongside level 1 and level 2 optimizations, e.g.
var myPlugin = {
level1: {
property: function removeRepeatedBackgroundRepeat(_rule, property, _options) {
if (property.name == 'background-repeat' && property.value.length == 2 && property.value[0][1] == property.value[1][1]) {
property.value.pop();
property.dirty = true;
}
}
}
}
new CleanCSS({plugins: [myPlugin]})
Search test\module-test.js
for plugins
or check out lib/optimizer/level-1/property-optimizers
and lib/optimizer/level-1/value-optimizers
for more examples.
Important: To rewrite your old transform
as a plugin, check out this commit.
Minify method
Once configured clean-css provides a minify
method to optimize a given CSS, e.g.
var output = new CleanCSS(options).minify(source);
The output of the minify
method is a hash with following fields:
console.log(output.styles);
console.log(output.sourceMap);
console.log(output.errors);
console.log(output.warnings);
console.log(output.stats.originalSize);
console.log(output.stats.minifiedSize);
console.log(output.stats.timeSpent);
console.log(output.stats.efficiency);
Example: Minifying a CSS string:
const CleanCSS = require("clean-css");
const output = new CleanCSS().minify(`
a {
color: blue;
}
div {
margin: 5px
}
`);
console.log(output);
{
styles: 'a{color:#00f}div{margin:5px}',
stats: {
efficiency: 0.6704545454545454,
minifiedSize: 29,
originalSize: 88,
timeSpent: 6
},
errors: [],
inlinedStylesheets: [],
warnings: []
}
The minify
method also accepts an input source map, e.g.
var output = new CleanCSS(options).minify(source, inputSourceMap);
or a callback invoked when optimizations are finished, e.g.
new CleanCSS(options).minify(source, function (error, output) {
});
To optimize a single file, without reading it first, pass a path to it to minify
method as follows:
var output = new CleanCSS(options).minify(['path/to/file.css'])
(if you won't enclose the path in an array, it will be treated as a CSS source instead).
There are several ways to optimize multiple files at the same time, see How to optimize multiple files?.
Promise interface
If you prefer clean-css to return a Promise object then you need to explicitely ask for it, e.g.
new CleanCSS({ returnPromise: true })
.minify(source)
.then(function (output) { console.log(output.styles); })
.catch(function (error) {
CLI utility
Clean-css has an associated command line utility that can be installed separately using npm install clean-css-cli
. For more detailed information, please visit https://github.com/clean-css/clean-css-cli.
FAQ
How to optimize multiple files?
It can be done either by passing an array of paths, or, when sources are already available, a hash or an array of hashes:
new CleanCSS().minify(['path/to/file/one', 'path/to/file/two']);
new CleanCSS().minify({
'path/to/file/one': {
styles: 'contents of file one'
},
'path/to/file/two': {
styles: 'contents of file two'
}
});
new CleanCSS().minify([
{'path/to/file/one': {styles: 'contents of file one'}},
{'path/to/file/two': {styles: 'contents of file two'}}
]);
Passing an array of hashes allows you to explicitly specify the order in which the input files are concatenated. Whereas when you use a single hash the order is determined by the traversal order of object properties - available since 4.1.0.
Important note - any @import
rules already present in the hash will be resolved in memory.
How to process multiple files without concatenating them into one output file?
Since clean-css 5.0 you can, when passing an array of paths, hash, or array of hashes (see above), ask clean-css not to join styles into one output, but instead return stylesheets optimized one by one, e.g.
var output = new CleanCSS({ batch: true }).minify(['path/to/file/one', 'path/to/file/two']);
var outputOfFile1 = output['path/to/file/one'].styles
var outputOfFile2 = output['path/to/file/two'].styles
How to process remote @import
s correctly?
In order to inline remote @import
statements you need to provide a callback to minify method as fetching remote assets is an asynchronous operation, e.g.:
var source = '@import url(http://example.com/path/to/remote/styles);';
new CleanCSS({ inline: ['remote'] }).minify(source, function (error, output) {
});
If you don't provide a callback, then remote @import
s will be left as is.
How to apply arbitrary transformations to CSS properties?
Please see plugins.
How to specify a custom rounding precision?
The level 1 roundingPrecision
optimization option accept a string with per-unit rounding precision settings, e.g.
new CleanCSS({
level: {
1: {
roundingPrecision: 'all=3,px=5'
}
}
}).minify(source)
which sets all units rounding precision to 3 digits except px
unit precision of 5 digits.
How to optimize a stylesheet with custom rpx
units?
Since rpx
is a non standard unit (see #1074), it will be dropped by default as an invalid value.
However you can treat rpx
units as regular ones:
new CleanCSS({
compatibility: {
customUnits: {
rpx: true
}
}
}).minify(source)
How to keep a CSS fragment intact?
Note: available since 4.2.0.
Wrap the CSS fragment in special comments which instruct clean-css to preserve it, e.g.
.block-1 {
color: red
}
.block-special {
color: transparent
}
.block-2 {
margin: 0
}
Optimizing this CSS will result in the following output:
.block-1{color:red}
.block-special {
color: transparent
}
.block-2{margin:0}
Use the /*!
notation instead of the standard one /*
:
How to rebase relative image URLs?
clean-css will handle it automatically for you in the following cases:
- when full paths to input files are passed in as options;
- when correct paths are passed in via a hash;
- when
rebaseTo
is used with any of above two.
How to work with source maps?
To generate a source map, use sourceMap: true
option, e.g.:
new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
.minify(source, function (error, output) {
});
You can also pass an input source map directly as a 2nd argument to minify
method:
new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
.minify(source, inputSourceMap, function (error, output) {
});
or even multiple input source maps at once:
new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory }).minify({
'path/to/source/1': {
styles: '...styles...',
sourceMap: '...source-map...'
},
'path/to/source/2': {
styles: '...styles...',
sourceMap: '...source-map...'
}
}, function (error, output) {
});
How to apply level 1 & 2 optimizations at the same time?
Using the hash configuration specifying both optimization levels, e.g.
new CleanCSS({
level: {
1: {
all: true,
normalizeUrls: false
},
2: {
restructureRules: true
}
}
})
will apply level 1 optimizations, except url normalization, and default level 2 optimizations with rule restructuring.
What level 2 optimizations do?
All level 2 optimizations are dispatched here, and this is what they do:
recursivelyOptimizeBlocks
- does all the following operations on a nested block, like @media
or @keyframe
;recursivelyOptimizeProperties
- optimizes properties in rulesets and flat at-rules, like @font-face, by splitting them into components (e.g. margin
into margin-(bottom|left|right|top)
), optimizing, and restoring them back. You may want to use mergeIntoShorthands
option to control whether you want to turn multiple components into shorthands;removeDuplicates
- gets rid of duplicate rulesets with exactly the same set of properties, e.g. when including a Sass / Less partial twice for no good reason;mergeAdjacent
- merges adjacent rulesets with the same selector or rules;reduceNonAdjacent
- identifies which properties are overridden in same-selector non-adjacent rulesets, and removes them;mergeNonAdjacentBySelector
- identifies same-selector non-adjacent rulesets which can be moved (!) to be merged, requires all intermediate rulesets to not redefine the moved properties, or if redefined to have the same value;mergeNonAdjacentByBody
- same as the one above but for same-selector non-adjacent rulesets;restructure
- tries to reorganize different-selector different-rules rulesets so they take less space, e.g. .one{padding:0}.two{margin:0}.one{margin-bottom:3px}
into .two{margin:0}.one{padding:0;margin-bottom:3px}
;removeDuplicateFontAtRules
- removes duplicated @font-face
rules;removeDuplicateMediaQueries
- removes duplicated @media
nested blocks;mergeMediaQueries
- merges non-adjacent @media
at-rules by the same rules as mergeNonAdjacentBy*
above;
What errors and warnings are?
If clean-css encounters invalid CSS, it will try to remove the invalid part and continue optimizing the rest of the code. It will make you aware of the problem by generating an error or warning. Although clean-css can work with invalid CSS, it is always recommended that you fix warnings and errors in your CSS.
Example: Minify invalid CSS, resulting in two warnings:
const CleanCSS = require("clean-css");
const output = new CleanCSS().minify(`
a {
-notarealproperty-: 5px;
color:
}
div {
margin: 5px
}
`);
console.log(output);
{
styles: 'div{margin:5px}',
stats: {
efficiency: 0.8695652173913043,
minifiedSize: 15,
originalSize: 115,
timeSpent: 1
},
errors: [],
inlinedStylesheets: [],
warnings: [
"Invalid property name '-notarealproperty-' at 4:8. Ignoring.",
"Empty property 'color' at 5:8. Ignoring."
]
}
Example: Minify invalid CSS, resulting in one error:
const CleanCSS = require("clean-css");
const output = new CleanCSS().minify(`
@import "idontexist.css";
a {
color: blue;
}
div {
margin: 5px
}
`);
console.log(output);
{
styles: 'a{color:#00f}div{margin:5px}',
stats: {
efficiency: 0.7627118644067796,
minifiedSize: 28,
originalSize: 118,
timeSpent: 2
},
errors: [
'Ignoring local @import of "idontexist.css" as resource is missing.'
],
inlinedStylesheets: [],
warnings: []
}
Clean-css for Gulp
An example of how you can include clean-css in gulp
const { src, dest, series } = require('gulp');
const CleanCSS = require('clean-css');
const concat = require('gulp-concat');
function css() {
const options = {
compatibility: '*',
inline: ['all'],
level: 2
};
return src('app/**/*.css')
.pipe(concat('style.min.css'))
.on('data', function(file) {
const buferFile = new CleanCSS(options).minify(file.contents)
return file.contents = Buffer.from(buferFile.styles)
})
.pipe(dest('build'))
}
exports.css = series(css)
How to use clean-css with build tools?
There is a number of 3rd party plugins to popular build tools:
How to use clean-css from web browser?
Contributing
See CONTRIBUTING.md.
How to get started?
First clone the sources:
git clone git@github.com:clean-css/clean-css.git
then install dependencies:
cd clean-css
npm install
then use any of the following commands to verify your copy:
npm run bench
npm run browserify
npm run check
npm test
Acknowledgments
Sorted alphabetically by GitHub handle:
- @abarre (Anthony Barre) for improvements to
@import
processing; - @alexlamsl (Alex Lam S.L.) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
- @altschuler (Simon Altschuler) for fixing
@import
processing inside comments; - @ben-eb (Ben Briggs) for sharing ideas about CSS optimizations;
- @davisjam (Jamie Davis) for disclosing ReDOS vulnerabilities;
- @facelessuser (Isaac) for pointing out a flaw in clean-css' stateless mode;
- @grandrath (Martin Grandrath) for improving
minify
method source traversal in ES6; - @jmalonzo (Jan Michael Alonzo) for a patch removing node.js' old
sys
package; - @lukeapage (Luke Page) for suggestions and testing the source maps feature;
Plus everyone else involved in #125 for pushing it forward;
- @madwizard-thomas for sharing ideas about
@import
inlining and URL rebasing. - @ngyikp (Ng Yik Phang) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
- @wagenet (Peter Wagenet) for suggesting improvements to
@import
inlining behavior; - @venemo (Timur Kristóf) for an outstanding contribution of advanced property optimizer for 2.2 release;
- @vvo (Vincent Voyer) for a patch with better empty element regex and for inspiring us to do many performance improvements in 0.4 release;
- @xhmikosr for suggesting new features, like option to remove special comments and strip out URLs quotation, and pointing out numerous improvements like JSHint, media queries, etc.
License
clean-css is released under the MIT License.