clean-css、cssnano、csso、minify、postcss-clean、uglifycss は、すべて CSS ファイルのサイズを削減し、ウェブサイトの読み込みパフォーマンスを最適化するためのツールです。これらは空白の削除、コメントの除去、プロパティの短縮などを行いますが、内部アルゴリズムや対応できる CSS の構文、そして他のビルドツールとの統合方法に大きな違いがあります。cssnano は PostCSS プラグインとして動作しエコシステムとの親和性が高く、clean-css と csso は高度な最適化アルゴリズムを持つスタンドアロンツールです。一方、uglifycss と minify はシンプルさを重視した軽量な選択肢ですが、機能面や保守状況において現代的な要件を満たさない場合があります。
CSS の最小化(Minification)は、ウェブパフォーマンス最適化の基本ですが、単に「空白を削る」だけではありません。clean-css、cssnano、csso、minify、postcss-clean、uglifycss は、それぞれ異なる哲学と技術的アプローチを持っています。開発者として重要なのは、単なる圧縮率だけでなく、ビルドパイプラインへの統合容易性、ソースマップの精度、そして現代の CSS 構文への対応力です。本稿では、これらのツールを実際のコード例と共に比較し、アーキテクチャ決定に役立つ洞察を提供します。
ツールの選び方で最も重要なのが、既存のビルドフローにどう組み込むかです。
cssnano は、PostCSS エコシステムの一部として設計されています。Webpack や Vite を使っている場合、設定ファイルに一行追加するだけで導入できます。
// webpack.config.js (cssnano の場合)
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [cssnano({ preset: 'default' })]
}
}
}
]
}
]
}
};
一方、clean-css はスタンドアロンで動作します。PostCSS を介さず、直接 CLI や API を呼び出せます。これは、Gulp や Grunt を使っている場合や、カスタムビルドスクリプトを書いている場合に有利です。
// Node.js API (clean-css の場合)
const CleanCSS = require('clean-css');
const source = 'body { color: red; }';
const output = new CleanCSS().minify(source);
console.log(output.styles); // "body{color:red}"
csso も同様にスタンドアロンですが、PostCSS プラグイン (postcss-csso) としても利用可能です。ただし、デフォルトでは単独での利用を想定した設計です。
# CLI (csso の場合)
csso input.css -o output.css
minify は、CSS だけでなく HTML や JS も処理できる多機能パッケージですが、CSS 処理に関しては専用ツールに比べて機能が限定的です。
// minify パッケージの使用例
const minify = require('minify');
minify('style.css')
.then(output => console.log(output))
.catch(error => console.error(error));
postcss-clean は、PostCSS 経由で clean-css を使うためのブリッジでしたが、現在はメンテナンスが停滞しており、公式には cssnano への移行が推奨されるケースが多いです。
uglifycss は、非常に古い設計で、現代のモジュールバンドラーとの統合には追加のラッパーが必要になることが多く、手間がかかります。
# uglifycss CLI
uglifycss style.css > output.css
各ツールは、CSS をどのように解析し、最適化するかが異なります。
clean-css は、レベル 1(基本的な削除)、レベル 2(選択子の最適化)、レベル 3(プロパティのマージ)の 3 段階の最適化レベルを提供します。特にレベル 2 以降では、重複するプロパティの削除や、フォント定義の短縮などを安全に行います。
// clean-css レベル 2 最適化
const source = `
.btn { color: red; }
.btn { background: blue; }
`;
// 出力: .btn{color:red;background:blue}
// 2 つのルールセットを安全にマージします
csso は、構文ツリー(AST)を深く解析し、よりアグレッシブな最適化を行います。例えば、選択子の並び順を変更して重複を減らしたり、0px を 0 に変換するだけでなく、rgba(0,0,0,0) を transparent に変換したりします。
/* 入力 */
.element {
margin: 0px 0px 0px 0px;
color: rgba(0, 0, 0, 0);
}
/* csso 出力 */
.element{margin:0;color:transparent}
cssnano は、内部で多くの PostCSS プラグイン(css-declaration-sorter や postcss-discard-comments など)を組み合わせて動作します。preset: 'advanced' を指定することで、csso に匹敵するほどの最適化が可能ですが、デフォルトは「安全性」を重視しています。
// cssnano 設定で高度な最適化を有効化
plugins: [
cssnano({
preset: ['advanced', { discardComments: { removeAll: true } }]
})
]
uglifycss は、正規表現ベースの単純な置換を多く使用しているため、複雑な最適化は行いません。主に空白とコメントの削除に留まります。
/* 入力 */
/* コメント */
body { color : red ; }
/* uglifycss 出力 */
body{color:red}
/* コメントは消えますが、構文的な最適化はほぼありません */
本番環境でのデバッグにはソースマップが不可欠です。
clean-css と cssnano は、高品質なソースマップ生成をサポートしています。特に clean-css は、元の行と列を正確にマッピングする能力に定評があります。
// clean-css でソースマップを生成
const output = new CleanCSS({
sourceMap: true,
sourceMapInlineSources: true
}).minify(source);
console.log(output.map); // 詳細なマップオブジェクト
csso もソースマップを生成できますが、最適化が激しい場合(選択子の並べ替えなど)、元のコードとの対応が少しわかりにくくなることがあります。
uglifycss と minify の CSS 機能は、ソースマップのサポートが弱いか、あるいはオプションとして提供されていないことが多いです。これは、大規模プロジェクトでは致命的な欠点となり得ます。
パッケージのメンテナンス状況は、長期プロジェクトにおいて重要です。
cssnano: 活発にメンテナンスされており、PostCSS コミュニティによって支えられています。新しい CSS 構文への対応も早いです。clean-css: 安定しており、定期的に更新されています。エンタープライズ環境での採用例も多いです。csso: 開発は継続されていますが、更新頻度はやや低めです。しかし、コアアルゴリズムは堅牢です。postcss-clean: 非推奨(Deprecated) のリスクが高いです。npm ページやリポジトリでアーカイブ扱いされている可能性があり、新規採用は避けるべきです。uglifycss: 長期間更新されていません。現代の CSS 機能(カスタムプロパティやネストなど)を正しく処理できないリスクがあります。minify: 更新はありますが、CSS 処理に関してはサブ機能としての扱いであり、専用ツールの追随が難しい場合があります。推奨: cssnano
理由:バンドラーとの統合がシームレスで、設定の手間が最小限です。PostCSS プラグインとして動作するため、Autoprefixer など他のツールとパイプラインを共有できます。
推奨: clean-css
理由:Gulp プラグイン (gulp-clean-css) が成熟しており、設定が直感的です。ソースマップの扱いも確実で、古いブラウザ向けのフォールバックを含めた安全な最適化が可能です。
推奨: csso
理由:数 KB を削る競争において、csso のアグレッシブなアルゴリズムが有利に働きます。ただし、表示崩れのリスクがあるため、入念なテストが必要です。
推奨: clean-css (API) または minify
理由:minify は複数フォーマット対応で便利ですが、CSS の品質を重視するなら clean-css の API を直接叩くのが無難です。uglifycss は避けるべきです。
現在のフロントエンド開発において、cssnano がデファクトスタンダードです。特にモダンなビルドツールを使用している場合、これを選ぶのが最も合理的です。安全性、機能、エコシステムのバランスが最も優れています。
一方、PostCSS に依存しない環境や、より詳細な制御が必要な場合は clean-css が強力な代替案となります。特にソースマップの精度と最適化の安全性を重視する大規模プロジェクトに適しています。
csso は特定のユースケース(サイズ最優先)で光りますが、一般的には cssnano の advanced preset で十分な場合が多いです。
最後に、uglifycss と postcss-clean は、特別な理由がない限り新規プロジェクトで使用すべきではありません。保守性の欠如と機能不足が、将来的な技術的負債になるリスクが高いためです。
最適なツールを選ぶことは、単にファイルサイズを減らすだけでなく、開発チームの生産性とプロダクトの長期メンテナンス性を高める決定です。プロジェクトの文脈に合わせて、これらの知見を活かしてください。
大規模な CSS コードベースを持ち、安全性と高度な最適化のバランスを重視するプロジェクトで選択します。ソースマップのサポートが充実しており、CLI や Node.js API から直接利用できるため、PostCSS を使わない従来のビルドパイプラインや、Gulp/Grunt などのタスクランナーと組み合わせる場合に最適です。
既に PostCSS を採用しているプロジェクト、または Webpack、Vite、Rollup などのモダンなバンドラーを使用している場合に首选します。生態系との統合が深く、Presets を通じて最適化レベルを細かく制御できるため、標準化されたワークフローの中で CSS 処理を一貫して管理したいチームに適しています。
ファイルサイズの削減率を最優先し、構文ツリーレベルでの agresive な最適化(選択子の並べ替えや重複の除去など)を必要とする場合に選択します。ただし、CSS 仕様のエッジケースや特殊な構文に対してリスクがあるため、十分なテスト環境が整っているプロジェクト向けです。
Node.js 環境内で CSS だけでなく HTML や JS も単一のライブラリで処理したい場合に検討しますが、CSS 専用ツールとしての機能深度は他より劣ります。依存関係を減らしたい小規模なスクリプトや、多機能な最小化ツールを軽く導入したい場合に限り有用です。
PostCSS パイプライン内で clean-css のエンジンを利用したい場合に選択しますが、現在は非推奨(deprecated)である可能性が高く、代わりに cssnano または postcss プラグインとしての公式サポートを待つべきです。新規プロジェクトでの採用は避け、既存レガシーコードの維持管理のみに限定すべきです。
極めて単純な CSS ファイルを素早く処理したい場合を除き、新規プロジェクトでの使用は推奨されません。長期間更新されておらず、現代の CSS 構文(変数、ネスト、カスタムプロパティなど)への対応が不十分であるため、信頼性と保守性の観点から他への移行を検討すべきです。
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
@imports correctly?clean-css requires Node.js 10.0+ (tested on Linux, OS X, and Windows)
npm install --save-dev clean-css
var CleanCSS = require('clean-css');
var input = 'a{font-weight:bold;}';
var options = { /* options */ };
var output = new CleanCSS(options).minify(input);
clean-css 5.3 introduces one new feature:
variableValueOptimizers option, which accepts a list of value optimizers or a list of their names, e.g. variableValueOptimizers: ['color', 'fraction'].clean-css 5.0 introduced some breaking changes:
transform callback in level-1 optimizations is removed in favor of new plugins interface;{ compatibility: 'ie10' } flag;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: {breaks: {afterComment: 2}} means clean-css will add two line breaks after each commentbatch 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.clean-css 4.2 introduces the following changes / features:
process method for compatibility with optimize-css-assets-webpack-plugin;transition property optimizer;/* clean-css ignore:start */ and /* clean-css ignore:end */ comments;transform callback, see example;format: { breakWith: 'lf' } option.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;font shorthand and font-* longhand optimizers;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;animation shorthand and animation-* longhand optimizers;removeUnusedAtRules level 2 optimization controlling removal of unused @counter-style, @font-face, @keyframes, and @namespace at rules;clean-css 4.0 introduces some breaking changes:
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;inliner: { request: ..., timeout: ... } option into inlineRequest and inlineTimeout options;//fonts.googleapis.com/css?family=Domine:700, are not inlined anymore;{ compatibility: 'ie9' } flag;keepSpecialComments to specialComments;roundingPrecision and specialComments to level 1 optimizations options, see examples;mediaMerging, restructuring, semanticMerging, and shorthandCompacting to level 2 optimizations options, see examples below;shorthandCompacting option to mergeIntoShorthands;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.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.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 modeEach of these modes is an alias to a fine grained configuration, with the following options available:
new CleanCSS({
compatibility: {
colors: {
hexAlpha: false, // controls 4- and 8-character hex color support
opacity: true // controls `rgba()` / `hsla()` color support
},
properties: {
backgroundClipMerging: true, // controls background-clip merging into shorthand
backgroundOriginMerging: true, // controls background-origin merging into shorthand
backgroundSizeMerging: true, // controls background-size merging into shorthand
colors: true, // controls color optimizations
ieBangHack: false, // controls keeping IE bang hack
ieFilters: false, // controls keeping IE `filter` / `-ms-filter`
iePrefixHack: false, // controls keeping IE prefix hack
ieSuffixHack: false, // controls keeping IE suffix hack
merging: true, // controls property merging based on understandability
shorterLengthUnits: false, // controls shortening pixel units into `pc`, `pt`, or `in` units
spaceAfterClosingBrace: true, // controls keeping space after closing brace - `url() no-repeat` into `url()no-repeat`
urlQuotes: true, // controls keeping quoting inside `url()`
zeroUnits: true // controls removal of units `0` value
},
selectors: {
adjacentSpace: false, // controls extra space before `nav` element
ie7Hack: true, // controls removal of IE7 selector hacks, e.g. `*+html...`
mergeablePseudoClasses: [':active', ...], // controls a whitelist of mergeable pseudo classes
mergeablePseudoElements: ['::after', ...], // controls a whitelist of mergeable pseudo elements
mergeLimit: 8191, // controls maximum number of selectors in a single rule (since 4.1.0)
multiplePseudoMerging: true // controls merging of rules with multiple pseudo classes / elements (since 4.1.0)
},
units: {
ch: true, // controls treating `ch` as a supported unit
in: true, // controls treating `in` as a supported unit
pc: true, // controls treating `pc` as a supported unit
pt: true, // controls treating `pt` as a supported unit
rem: true, // controls treating `rem` as a supported unit
vh: true, // controls treating `vh` as a supported unit
vm: true, // controls treating `vm` as a supported unit
vmax: true, // controls treating `vmax` as a supported unit
vmin: true // controls treating `vmin` as a supported unit
}
}
})
You can also use a string when setting a compatibility mode, e.g.
new CleanCSS({
compatibility: 'ie9,-properties.merging' // sets compatibility to IE9 mode with disabled property merging
})
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.
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' // formats output in a really nice way
})
and
new CleanCSS({
format: 'keep-breaks' // formats output the default way but adds line breaks for improved readability
})
however format option also accept a fine-grained set of options:
new CleanCSS({
format: {
breaks: { // controls where to insert breaks
afterAtRule: false, // controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `false`
afterBlockBegins: false, // controls if a line break comes after a block begins; e.g. `@media`; defaults to `false`
afterBlockEnds: false, // controls if a line break comes after a block ends, defaults to `false`
afterComment: false, // controls if a line break comes after a comment; defaults to `false`
afterProperty: false, // controls if a line break comes after a property; defaults to `false`
afterRuleBegins: false, // controls if a line break comes after a rule begins; defaults to `false`
afterRuleEnds: false, // controls if a line break comes after a rule ends; defaults to `false`
beforeBlockEnds: false, // controls if a line break comes before a block ends; defaults to `false`
betweenSelectors: false // controls if a line break comes between selectors; defaults to `false`
},
breakWith: '\n', // controls the new line character, can be `'\r\n'` or `'\n'` (aliased as `'windows'` and `'unix'` or `'crlf'` and `'lf'`); defaults to system one, so former on Windows and latter on Unix
indentBy: 0, // controls number of characters to indent with; defaults to `0`
indentWith: 'space', // controls a character to indent with, can be `'space'` or `'tab'`; defaults to `'space'`
spaces: { // controls where to insert spaces
aroundSelectorRelation: false, // controls if spaces come around selector relations; e.g. `div > a`; defaults to `false`
beforeBlockBegins: false, // controls if a space comes before a block begins; e.g. `.block {`; defaults to `false`
beforeValue: false // controls if a space comes before a value; e.g. `width: 1rem`; defaults to `false`
},
wrapAt: false, // controls maximum line length; defaults to `false`
semicolonAfterLastProperty: false // controls removing trailing semicolons in rule; defaults to `false` - means remove
}
})
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, // 1 is synonymous with `true`
afterBlockEnds: 2,
afterComment: 1,
afterProperty: 1,
afterRuleBegins: 1,
afterRuleEnds: 1,
beforeBlockEnds: 1,
betweenSelectors: 0 // 0 is synonymous with `false`
}
}
})
which will add nicer spacing between at rules and blocks.
inline option whitelists which @import rules will be processed, e.g.
new CleanCSS({
inline: ['local'] // default; enables local inlining only
})
new CleanCSS({
inline: ['none'] // disables all inlining
})
// introduced in clean-css 4.1.0
new CleanCSS({
inline: false // disables all inlining (alias to `['none']`)
})
new CleanCSS({
inline: ['all'] // enables all inlining, same as ['local', 'remote']
})
new CleanCSS({
inline: ['local', 'mydomain.example.com'] // enables local inlining plus given remote source
})
new CleanCSS({
inline: ['local', 'remote', '!fonts.googleapis.com'] // enables all inlining but from given remote source
})
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 simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else.
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, // controls `@charset` moving to the front of a stylesheet; defaults to `true`
normalizeUrls: true, // controls URL normalization; defaults to `true`
optimizeBackground: true, // controls `background` property optimizations; defaults to `true`
optimizeBorderRadius: true, // controls `border-radius` property optimizations; defaults to `true`
optimizeFilter: true, // controls `filter` property optimizations; defaults to `true`
optimizeFont: true, // controls `font` property optimizations; defaults to `true`
optimizeFontWeight: true, // controls `font-weight` property optimizations; defaults to `true`
optimizeOutline: true, // controls `outline` property optimizations; defaults to `true`
removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
removeNegativePaddings: true, // controls removing negative paddings; defaults to `true`
removeQuotes: true, // controls removing quotes when unnecessary; defaults to `true`
removeWhitespace: true, // controls removing unused whitespace; defaults to `true`
replaceMultipleZeros: true, // contols removing redundant zeros; defaults to `true`
replaceTimeUnits: true, // controls replacing time units with shorter values; defaults to `true`
replaceZeroUnits: true, // controls replacing zero values with units; defaults to `true`
roundingPrecision: false, // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`
selectorsSortingMethod: 'standard', // denotes selector sorting method; can be `'natural'` or `'standard'`, `'none'`, or false (the last two since 4.1.0); defaults to `'standard'`
specialComments: 'all', // denotes a number of /*! ... */ comments preserved; defaults to `all`
tidyAtRules: true, // controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`
tidyBlockScopes: true, // controls block scopes (e.g. `@media`) optimizing; defaults to `true`
tidySelectors: true, // controls selectors optimizing; defaults to `true`,
variableValueOptimizers: [] // controls value optimizers which are applied to variables
}
}
});
There is an all shortcut for toggling all options at the same time, e.g.
new CleanCSS({
level: {
1: {
all: false, // set all values to `false`
tidySelectors: true // turns on optimizing selectors
}
}
});
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, // controls adjacent rules merging; defaults to true
mergeIntoShorthands: true, // controls merging properties into shorthands; defaults to true
mergeMedia: true, // controls `@media` merging; defaults to true
mergeNonAdjacentRules: true, // controls non-adjacent rule merging; defaults to true
mergeSemantically: false, // controls semantic merging; defaults to false
overrideProperties: true, // controls property overriding based on understandability; defaults to true
removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
reduceNonAdjacentRules: true, // controls non-adjacent rule reducing; defaults to true
removeDuplicateFontRules: true, // controls duplicate `@font-face` removing; defaults to true
removeDuplicateMediaBlocks: true, // controls duplicate `@media` removing; defaults to true
removeDuplicateRules: true, // controls duplicate rules removing; defaults to true
removeUnusedAtRules: false, // controls unused at rule removing; defaults to false (available since 4.1.0)
restructureRules: false, // controls rule restructuring; defaults to false
skipProperties: [] // controls which properties won't be optimized, defaults to `[]` which means all will be optimized (since 4.1.0)
}
}
});
There is an all shortcut for toggling all options at the same time, e.g.
new CleanCSS({
level: {
2: {
all: false, // sets all values to `false`
removeDuplicateRules: true // turns on removing duplicate rules
}
}
});
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) {
// So `background-repeat:no-repeat no-repeat` becomes `background-repeat:no-repeat`
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.
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); // optimized output CSS as a string
console.log(output.sourceMap); // output source map if requested with `sourceMap` option
console.log(output.errors); // a list of errors raised
console.log(output.warnings); // a list of warnings raised
console.log(output.stats.originalSize); // original content size after import inlining
console.log(output.stats.minifiedSize); // optimized content size
console.log(output.stats.timeSpent); // time spent on optimizations in milliseconds
console.log(output.stats.efficiency); // `(originalSize - minifiedSize) / originalSize`, e.g. 0.25 if size is reduced from 100 bytes to 75 bytes
Example: Minifying a CSS string:
const CleanCSS = require("clean-css");
const output = new CleanCSS().minify(`
a {
color: blue;
}
div {
margin: 5px
}
`);
console.log(output);
// Log:
{
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) {
// `output` is the same as in the synchronous call above
});
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?.
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) { // deal with errors });
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.
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.
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 // all other fields, like errors, warnings, or stats are there too
var outputOfFile2 = output['path/to/file/two'].styles
@imports 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) {
// output.styles
});
If you don't provide a callback, then remote @imports will be left as is.
Please see plugins.
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.
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)
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
}
/* clean-css ignore:start */
.block-special {
color: transparent
}
/* clean-css ignore:end */
.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 /*:
/*!
Important comments included in optimized output.
*/
clean-css will handle it automatically for you in the following cases:
rebaseTo is used with any of above two.To generate a source map, use sourceMap: true option, e.g.:
new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
.minify(source, function (error, output) {
// access output.sourceMap for SourceMapGenerator object
// see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
});
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) {
// access output.sourceMap to access SourceMapGenerator object
// see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
});
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) {
// access output.sourceMap as above
});
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.
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;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);
// Log:
{
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);
// Log:
{
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: []
}
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: '*', // (default) - Internet Explorer 10+ compatibility mode
inline: ['all'], // enables all inlining, same as ['local', 'remote']
level: 2 // Optimization levels. The level option can be either 0, 1 (default), or 2, e.g.
// Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
};
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)
There is a number of 3rd party plugins to popular build tools:
See CONTRIBUTING.md.
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 # for clean-css benchmarks (see [test/bench.js](https://github.com/clean-css/clean-css/blob/master/test/bench.js) for details)
npm run browserify # to create the browser-ready clean-css version
npm run check # to lint JS sources with [JSHint](https://github.com/jshint/jshint/)
npm test # to run all tests
Sorted alphabetically by GitHub handle:
@import processing;@import processing inside comments;minify method source traversal in ES6;sys package;@import inlining and URL rebasing.@import inlining behavior;clean-css is released under the MIT License.