UNPKG

40.5 kBMarkdownView Raw
1<h1 align="center">
2 <br/>
3 <img src="./logo.v2.svg" alt="clean-css logo" width="525px"/>
4 <br/>
5 <br/>
6</h1>
7
8[![npm version](https://img.shields.io/npm/v/clean-css.svg?style=flat)](https://www.npmjs.com/package/clean-css)
9[![Build Status](https://img.shields.io/github/workflow/status/clean-css/clean-css/Tests/master)](https://github.com/clean-css/clean-css/actions?query=workflow%3ATests+branch%3Amaster)
10[![PPC Linux Build Status](https://img.shields.io/travis/clean-css/clean-css/master.svg?style=flat&label=PPC%20Linux%20build)](https://travis-ci.org/clean-css/clean-css)
11[![Dependency Status](https://img.shields.io/david/clean-css/clean-css.svg?style=flat)](https://david-dm.org/clean-css/clean-css)
12[![npm Downloads](https://img.shields.io/npm/dm/clean-css.svg)](https://npmcharts.com/compare/clean-css?minimal=true)
13
14clean-css is a fast and efficient CSS optimizer for [Node.js](http://nodejs.org/) platform and [any modern browser](https://clean-css.github.io/).
15
16According to [tests](http://goalsmashers.github.io/css-minification-benchmark/) it is one of the best available.
17
18**Table of Contents**
19
20- [Node.js version support](#nodejs-version-support)
21- [Install](#install)
22- [Use](#use)
23 * [What's new in version 5.0](#whats-new-in-version-50)
24 * [What's new in version 4.2](#whats-new-in-version-42)
25 * [What's new in version 4.1](#whats-new-in-version-41)
26 * [Important: 4.0 breaking changes](#important-40-breaking-changes)
27 * [Constructor options](#constructor-options)
28 * [Compatibility modes](#compatibility-modes)
29 * [Fetch option](#fetch-option)
30 * [Formatting options](#formatting-options)
31 * [Inlining options](#inlining-options)
32 * [Optimization levels](#optimization-levels)
33 + [Level 0 optimizations](#level-0-optimizations)
34 + [Level 1 optimizations](#level-1-optimizations)
35 + [Level 2 optimizations](#level-2-optimizations)
36 * [Plugins](#plugins)
37 * [Minify method](#minify-method)
38 * [Promise interface](#promise-interface)
39 * [CLI utility](#cli-utility)
40- [FAQ](#faq)
41 * [How to optimize multiple files?](#how-to-optimize-multiple-files)
42 * [How to process multiple files without concatenating them into one output file?](#how-to-process-multiple-files-without-concatenating-them-into-one-output-file)
43 * [How to process remote `@import`s correctly?](#how-to-process-remote-imports-correctly)
44 * [How to apply arbitrary transformations to CSS properties?](#how-to-apply-arbitrary-transformations-to-css-properties)
45 * [How to specify a custom rounding precision?](#how-to-specify-a-custom-rounding-precision)
46 * [How to keep a CSS fragment intact?](#how-to-keep-a-css-fragment-intact)
47 * [How to preserve a comment block?](#how-to-preserve-a-comment-block)
48 * [How to rebase relative image URLs?](#how-to-rebase-relative-image-urls)
49 * [How to work with source maps?](#how-to-work-with-source-maps)
50 * [How to apply level 1 & 2 optimizations at the same time?](#how-to-apply-level-1--2-optimizations-at-the-same-time)
51 * [What level 2 optimizations do?](#what-level-2-optimizations-do)
52 * [What errors and warnings are?](#what-errors-and-warnings-are)
53 * [How to use clean-css with build tools?](#how-to-use-clean-css-with-build-tools)
54 * [How to use clean-css from web browser?](#how-to-use-clean-css-from-web-browser)
55- [Contributing](#contributing)
56 * [How to get started?](#how-to-get-started)
57- [Acknowledgments](#acknowledgments)
58- [License](#license)
59
60# Node.js version support
61
62clean-css requires Node.js 10.0+ (tested on Linux, OS X, and Windows)
63
64# Install
65
66```
67npm install --save-dev clean-css
68```
69
70# Use
71
72```js
73var CleanCSS = require('clean-css');
74var input = 'a{font-weight:bold;}';
75var options = { /* options */ };
76var output = new CleanCSS(options).minify(input);
77```
78
79## What's new in version 5.0
80
81clean-css 5.0 will introduce some breaking changes:
82
83* Node.js 6.x and 8.x are officially no longer supported;
84* `transform` callback in level-1 optimizations is removed in favor of new [plugins](#plugins) interface;
85* changes default Internet Explorer compatibility from 10+ to >11, to revert the old default use `{ compatibility: 'ie10' }` flag;
86* 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.
87
88And on the new features side of things:
89
90* 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
91* 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.
92
93## What's new in version 4.2
94
95clean-css 4.2 introduces the following changes / features:
96
97* Adds `process` method for compatibility with optimize-css-assets-webpack-plugin;
98* new `transition` property optimizer;
99* preserves any CSS content between `/* clean-css ignore:start */` and `/* clean-css ignore:end */` comments;
100* allows filtering based on selector in `transform` callback, see [example](#how-to-apply-arbitrary-transformations-to-css-properties);
101* adds configurable line breaks via `format: { breakWith: 'lf' }` option.
102
103## What's new in version 4.1
104
105clean-css 4.1 introduces the following changes / features:
106
107* `inline: false` as an alias to `inline: ['none']`;
108* `multiplePseudoMerging` compatibility flag controlling merging of rules with multiple pseudo classes / elements;
109* `removeEmpty` flag in level 1 optimizations controlling removal of rules and nested blocks;
110* `removeEmpty` flag in level 2 optimizations controlling removal of rules and nested blocks;
111* `compatibility: { selectors: { mergeLimit: <number> } }` flag in compatibility settings controlling maximum number of selectors in a single rule;
112* `minify` method improved signature accepting a list of hashes for a predictable traversal;
113* `selectorsSortingMethod` level 1 optimization allows `false` or `'none'` for disabling selector sorting;
114* `fetch` option controlling a function for handling remote requests;
115* new `font` shorthand and `font-*` longhand optimizers;
116* removal of `optimizeFont` flag in level 1 optimizations due to new `font` shorthand optimizer;
117* `skipProperties` flag in level 2 optimizations controlling which properties won't be optimized;
118* new `animation` shorthand and `animation-*` longhand optimizers;
119* `removeUnusedAtRules` level 2 optimization controlling removal of unused `@counter-style`, `@font-face`, `@keyframes`, and `@namespace` at rules;
120* the [web interface](https://clean-css.github.io/) gets an improved settings panel with "reset to defaults", instant option changes, and settings being persisted across sessions.
121
122## Important: 4.0 breaking changes
123
124clean-css 4.0 introduces some breaking changes:
125
126* API and CLI interfaces are split, so API stays in this repository while CLI moves to [clean-css-cli](https://github.com/clean-css/clean-css-cli);
127* `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;
128* `debug` option is gone as stats are always provided in output object under `stats` property;
129* `roundingPrecision` is disabled by default;
130* `roundingPrecision` applies to **all** units now, not only `px` as in 3.x;
131* `processImport` and `processImportFrom` are merged into `inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore;
132* splits `inliner: { request: ..., timeout: ... }` option into `inlineRequest` and `inlineTimeout` options;
133* remote resources without a protocol, e.g. `//fonts.googleapis.com/css?family=Domine:700`, are not inlined anymore;
134* changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use `{ compatibility: 'ie9' }` flag;
135* renames `keepSpecialComments` to `specialComments`;
136* moves `roundingPrecision` and `specialComments` to level 1 optimizations options, see examples;
137* moves `mediaMerging`, `restructuring`, `semanticMerging`, and `shorthandCompacting` to level 2 optimizations options, see examples below;
138* renames `shorthandCompacting` option to `mergeIntoShorthands`;
139* level 1 optimizations are the new default, up to 3.x it was level 2;
140* `keepBreaks` option is replaced with `{ format: 'keep-breaks' }` to ease transition;
141* `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;
142* `aggressiveMerging` option is removed as aggressive merging is replaced by smarter override merging.
143
144## Constructor options
145
146clean-css constructor accepts a hash as a parameter with the following options available:
147
148* `compatibility` - controls compatibility mode used; defaults to `ie10+`; see [compatibility modes](#compatibility-modes) for examples;
149* `fetch` - controls a function for handling remote requests; see [fetch option](#fetch-option) for examples (since 4.1.0);
150* `format` - controls output CSS formatting; defaults to `false`; see [formatting options](#formatting-options) for examples;
151* `inline` - controls `@import` inlining rules; defaults to `'local'`; see [inlining options](#inlining-options) for examples;
152* `inlineRequest` - controls extra options for inlining remote `@import` rules, can be any of [HTTP(S) request options](https://nodejs.org/api/http.html#http_http_request_options_callback);
153* `inlineTimeout` - controls number of milliseconds after which inlining a remote `@import` fails; defaults to 5000;
154* `level` - controls optimization level used; defaults to `1`; see [optimization levels](#optimization-levels) for examples;
155* `rebase` - controls URL rebasing; defaults to `false`;
156* `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;
157* `returnPromise` - controls whether `minify` method returns a Promise object or not; defaults to `false`; see [promise interface](#promise-interface) for examples;
158* `sourceMap` - controls whether an output source map is built; defaults to `false`;
159* `sourceMapInlineSources` - controls embedding sources inside a source map's `sourcesContent` field; defaults to false.
160
161## Compatibility modes
162
163There is a certain number of compatibility mode shortcuts, namely:
164
165* `new CleanCSS({ compatibility: '*' })` (default) - Internet Explorer 10+ compatibility mode
166* `new CleanCSS({ compatibility: 'ie9' })` - Internet Explorer 9+ compatibility mode
167* `new CleanCSS({ compatibility: 'ie8' })` - Internet Explorer 8+ compatibility mode
168* `new CleanCSS({ compatibility: 'ie7' })` - Internet Explorer 7+ compatibility mode
169
170Each of these modes is an alias to a [fine grained configuration](https://github.com/clean-css/clean-css/blob/master/lib/options/compatibility.js), with the following options available:
171
172```js
173new CleanCSS({
174 compatibility: {
175 colors: {
176 hexAlpha: false, // controls 4- and 8-character hex color support
177 opacity: true // controls `rgba()` / `hsla()` color support
178 },
179 properties: {
180 backgroundClipMerging: true, // controls background-clip merging into shorthand
181 backgroundOriginMerging: true, // controls background-origin merging into shorthand
182 backgroundSizeMerging: true, // controls background-size merging into shorthand
183 colors: true, // controls color optimizations
184 ieBangHack: false, // controls keeping IE bang hack
185 ieFilters: false, // controls keeping IE `filter` / `-ms-filter`
186 iePrefixHack: false, // controls keeping IE prefix hack
187 ieSuffixHack: false, // controls keeping IE suffix hack
188 merging: true, // controls property merging based on understandability
189 shorterLengthUnits: false, // controls shortening pixel units into `pc`, `pt`, or `in` units
190 spaceAfterClosingBrace: true, // controls keeping space after closing brace - `url() no-repeat` into `url()no-repeat`
191 urlQuotes: true, // controls keeping quoting inside `url()`
192 zeroUnits: true // controls removal of units `0` value
193 },
194 selectors: {
195 adjacentSpace: false, // controls extra space before `nav` element
196 ie7Hack: true, // controls removal of IE7 selector hacks, e.g. `*+html...`
197 mergeablePseudoClasses: [':active', ...], // controls a whitelist of mergeable pseudo classes
198 mergeablePseudoElements: ['::after', ...], // controls a whitelist of mergeable pseudo elements
199 mergeLimit: 8191, // controls maximum number of selectors in a single rule (since 4.1.0)
200 multiplePseudoMerging: true // controls merging of rules with multiple pseudo classes / elements (since 4.1.0)
201 },
202 units: {
203 ch: true, // controls treating `ch` as a supported unit
204 in: true, // controls treating `in` as a supported unit
205 pc: true, // controls treating `pc` as a supported unit
206 pt: true, // controls treating `pt` as a supported unit
207 rem: true, // controls treating `rem` as a supported unit
208 vh: true, // controls treating `vh` as a supported unit
209 vm: true, // controls treating `vm` as a supported unit
210 vmax: true, // controls treating `vmax` as a supported unit
211 vmin: true // controls treating `vmin` as a supported unit
212 }
213 }
214})
215```
216
217You can also use a string when setting a compatibility mode, e.g.
218
219```js
220new CleanCSS({
221 compatibility: 'ie9,-properties.merging' // sets compatibility to IE9 mode with disabled property merging
222})
223```
224
225## Fetch option
226
227The `fetch` option accepts a function which handles remote resource fetching, e.g.
228
229```js
230var request = require('request');
231var source = '@import url(http://example.com/path/to/stylesheet.css);';
232new CleanCSS({
233 fetch: function (uri, inlineRequest, inlineTimeout, callback) {
234 request(uri, function (error, response, body) {
235 if (error) {
236 callback(error, null);
237 } else if (response && response.statusCode != 200) {
238 callback(response.statusCode, null);
239 } else {
240 callback(null, body);
241 }
242 });
243 }
244}).minify(source);
245```
246
247This option provides a convenient way of overriding the default fetching logic if it doesn't support a particular feature, say CONNECT proxies.
248
249Unless given, the default [loadRemoteResource](https://github.com/clean-css/clean-css/blob/master/lib/reader/load-remote-resource.js) logic is used.
250
251## Formatting options
252
253By default output CSS is formatted without any whitespace unless a `format` option is given.
254First of all there are two shorthands:
255
256```js
257new CleanCSS({
258 format: 'beautify' // formats output in a really nice way
259})
260```
261
262and
263
264```js
265new CleanCSS({
266 format: 'keep-breaks' // formats output the default way but adds line breaks for improved readability
267})
268```
269
270however `format` option also accept a fine-grained set of options:
271
272```js
273new CleanCSS({
274 format: {
275 breaks: { // controls where to insert breaks
276 afterAtRule: false, // controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `false`
277 afterBlockBegins: false, // controls if a line break comes after a block begins; e.g. `@media`; defaults to `false`
278 afterBlockEnds: false, // controls if a line break comes after a block ends, defaults to `false`
279 afterComment: false, // controls if a line break comes after a comment; defaults to `false`
280 afterProperty: false, // controls if a line break comes after a property; defaults to `false`
281 afterRuleBegins: false, // controls if a line break comes after a rule begins; defaults to `false`
282 afterRuleEnds: false, // controls if a line break comes after a rule ends; defaults to `false`
283 beforeBlockEnds: false, // controls if a line break comes before a block ends; defaults to `false`
284 betweenSelectors: false // controls if a line break comes between selectors; defaults to `false`
285 },
286 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
287 indentBy: 0, // controls number of characters to indent with; defaults to `0`
288 indentWith: 'space', // controls a character to indent with, can be `'space'` or `'tab'`; defaults to `'space'`
289 spaces: { // controls where to insert spaces
290 aroundSelectorRelation: false, // controls if spaces come around selector relations; e.g. `div > a`; defaults to `false`
291 beforeBlockBegins: false, // controls if a space comes before a block begins; e.g. `.block {`; defaults to `false`
292 beforeValue: false // controls if a space comes before a value; e.g. `width: 1rem`; defaults to `false`
293 },
294 wrapAt: false, // controls maximum line length; defaults to `false`
295 semicolonAfterLastProperty: false // controls removing trailing semicolons in rule; defaults to `false` - means remove
296 }
297})
298```
299
300Also 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:
301
302```js
303 new CleanCSS({
304 format: {
305 breaks: {
306 afterAtRule: 2,
307 afterBlockBegins: 1, // 1 is synonymous with `true`
308 afterBlockEnds: 2,
309 afterComment: 1,
310 afterProperty: 1,
311 afterRuleBegins: 1,
312 afterRuleEnds: 1,
313 beforeBlockEnds: 1,
314 betweenSelectors: 0 // 0 is synonymous with `false`
315 }
316 }
317 })
318```
319
320which will add nicer spacing between at rules and blocks.
321
322## Inlining options
323
324`inline` option whitelists which `@import` rules will be processed, e.g.
325
326```js
327new CleanCSS({
328 inline: ['local'] // default; enables local inlining only
329})
330```
331
332```js
333new CleanCSS({
334 inline: ['none'] // disables all inlining
335})
336```
337
338```js
339// introduced in clean-css 4.1.0
340
341new CleanCSS({
342 inline: false // disables all inlining (alias to `['none']`)
343})
344```
345
346```js
347new CleanCSS({
348 inline: ['all'] // enables all inlining, same as ['local', 'remote']
349})
350```
351
352```js
353new CleanCSS({
354 inline: ['local', 'mydomain.example.com'] // enables local inlining plus given remote source
355})
356```
357
358```js
359new CleanCSS({
360 inline: ['local', 'remote', '!fonts.googleapis.com'] // enables all inlining but from given remote source
361})
362```
363
364## Optimization levels
365
366The `level` option can be either `0`, `1` (default), or `2`, e.g.
367
368```js
369new CleanCSS({
370 level: 2
371})
372```
373
374or a fine-grained configuration given via a hash.
375
376Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
377
378### Level 0 optimizations
379
380Level 0 optimizations simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else.
381
382### Level 1 optimizations
383
384Level 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
385
386Here is a full list of available options:
387
388```js
389new CleanCSS({
390 level: {
391 1: {
392 cleanupCharsets: true, // controls `@charset` moving to the front of a stylesheet; defaults to `true`
393 normalizeUrls: true, // controls URL normalization; defaults to `true`
394 optimizeBackground: true, // controls `background` property optimizations; defaults to `true`
395 optimizeBorderRadius: true, // controls `border-radius` property optimizations; defaults to `true`
396 optimizeFilter: true, // controls `filter` property optimizations; defaults to `true`
397 optimizeFont: true, // controls `font` property optimizations; defaults to `true`
398 optimizeFontWeight: true, // controls `font-weight` property optimizations; defaults to `true`
399 optimizeOutline: true, // controls `outline` property optimizations; defaults to `true`
400 removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
401 removeNegativePaddings: true, // controls removing negative paddings; defaults to `true`
402 removeQuotes: true, // controls removing quotes when unnecessary; defaults to `true`
403 removeWhitespace: true, // controls removing unused whitespace; defaults to `true`
404 replaceMultipleZeros: true, // contols removing redundant zeros; defaults to `true`
405 replaceTimeUnits: true, // controls replacing time units with shorter values; defaults to `true`
406 replaceZeroUnits: true, // controls replacing zero values with units; defaults to `true`
407 roundingPrecision: false, // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`
408 selectorsSortingMethod: 'standard', // denotes selector sorting method; can be `'natural'` or `'standard'`, `'none'`, or false (the last two since 4.1.0); defaults to `'standard'`
409 specialComments: 'all', // denotes a number of /*! ... */ comments preserved; defaults to `all`
410 tidyAtRules: true, // controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`
411 tidyBlockScopes: true, // controls block scopes (e.g. `@media`) optimizing; defaults to `true`
412 tidySelectors: true, // controls selectors optimizing; defaults to `true`
413 }
414 }
415});
416```
417
418There is an `all` shortcut for toggling all options at the same time, e.g.
419
420```js
421new CleanCSS({
422 level: {
423 1: {
424 all: false, // set all values to `false`
425 tidySelectors: true // turns on optimizing selectors
426 }
427 }
428});
429```
430
431### Level 2 optimizations
432
433Level 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.
434
435Please note that if level 2 optimizations are turned on then, unless explicitely disabled, level 1 optimizations are applied as well.
436
437Here is a full list of available options:
438
439```js
440new CleanCSS({
441 level: {
442 2: {
443 mergeAdjacentRules: true, // controls adjacent rules merging; defaults to true
444 mergeIntoShorthands: true, // controls merging properties into shorthands; defaults to true
445 mergeMedia: true, // controls `@media` merging; defaults to true
446 mergeNonAdjacentRules: true, // controls non-adjacent rule merging; defaults to true
447 mergeSemantically: false, // controls semantic merging; defaults to false
448 overrideProperties: true, // controls property overriding based on understandability; defaults to true
449 removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
450 reduceNonAdjacentRules: true, // controls non-adjacent rule reducing; defaults to true
451 removeDuplicateFontRules: true, // controls duplicate `@font-face` removing; defaults to true
452 removeDuplicateMediaBlocks: true, // controls duplicate `@media` removing; defaults to true
453 removeDuplicateRules: true, // controls duplicate rules removing; defaults to true
454 removeUnusedAtRules: false, // controls unused at rule removing; defaults to false (available since 4.1.0)
455 restructureRules: false, // controls rule restructuring; defaults to false
456 skipProperties: [] // controls which properties won't be optimized, defaults to `[]` which means all will be optimized (since 4.1.0)
457 }
458 }
459});
460```
461
462There is an `all` shortcut for toggling all options at the same time, e.g.
463
464```js
465new CleanCSS({
466 level: {
467 2: {
468 all: false, // sets all values to `false`
469 removeDuplicateRules: true // turns on removing duplicate rules
470 }
471 }
472});
473```
474
475## Plugins
476
477In clean-css version 5 and above you can define plugins which run alongside level 1 and level 2 optimizations, e.g.
478
479```js
480var myPlugin = {
481 level1: {
482 property: function removeRepeatedBackgroundRepeat(_rule, property, _options) {
483 // So `background-repeat:no-repeat no-repeat` becomes `background-repeat:no-repeat`
484 if (property.name == 'background-repeat' && property.value.length == 2 && property.value[0][1] == property.value[1][1]) {
485 property.value.pop();
486 property.dirty = true;
487 }
488 }
489 }
490}
491
492new CleanCSS({plugins: [myPlugin]})
493
494```
495
496Search `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.
497
498__Important__: To rewrite your old `transform` as a plugin, check out [this commit](https://github.com/clean-css/clean-css/commit/b6ddc523267fc42cf0f6bd1626a79cad97319e17#diff-a71ef45f934725cdb25860dc0b606bcd59e3acee9788cd6df4f9d05339e8a153).
499
500## Minify method
501
502Once configured clean-css provides a `minify` method to optimize a given CSS, e.g.
503
504```js
505var output = new CleanCSS(options).minify(source);
506```
507
508The output of the `minify` method is a hash with following fields:
509
510```js
511console.log(output.styles); // optimized output CSS as a string
512console.log(output.sourceMap); // output source map if requested with `sourceMap` option
513console.log(output.errors); // a list of errors raised
514console.log(output.warnings); // a list of warnings raised
515console.log(output.stats.originalSize); // original content size after import inlining
516console.log(output.stats.minifiedSize); // optimized content size
517console.log(output.stats.timeSpent); // time spent on optimizations in milliseconds
518console.log(output.stats.efficiency); // `(originalSize - minifiedSize) / originalSize`, e.g. 0.25 if size is reduced from 100 bytes to 75 bytes
519```
520Example: Minifying a CSS string:
521
522```js
523const CleanCSS = require("clean-css");
524
525const output = new CleanCSS().minify(`
526
527 a {
528 color: blue;
529 }
530 div {
531 margin: 5px
532 }
533
534`);
535
536console.log(output);
537
538// Log:
539{
540 styles: 'a{color:#00f}div{margin:5px}',
541 stats: {
542 efficiency: 0.6704545454545454,
543 minifiedSize: 29,
544 originalSize: 88,
545 timeSpent: 6
546 },
547 errors: [],
548 inlinedStylesheets: [],
549 warnings: []
550}
551```
552
553The `minify` method also accepts an input source map, e.g.
554
555```js
556var output = new CleanCSS(options).minify(source, inputSourceMap);
557```
558
559or a callback invoked when optimizations are finished, e.g.
560
561```js
562new CleanCSS(options).minify(source, function (error, output) {
563 // `output` is the same as in the synchronous call above
564});
565```
566
567## Promise interface
568
569If you prefer clean-css to return a Promise object then you need to explicitely ask for it, e.g.
570
571```js
572new CleanCSS({ returnPromise: true })
573 .minify(source)
574 .then(function (output) { console.log(output.styles); })
575 .catch(function (error) { // deal with errors });
576```
577
578## CLI utility
579
580Clean-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.
581
582# FAQ
583
584## How to optimize multiple files?
585
586It can be done either by passing an array of paths, or, when sources are already available, a hash or an array of hashes:
587
588```js
589new CleanCSS().minify(['path/to/file/one', 'path/to/file/two']);
590```
591
592```js
593new CleanCSS().minify({
594 'path/to/file/one': {
595 styles: 'contents of file one'
596 },
597 'path/to/file/two': {
598 styles: 'contents of file two'
599 }
600});
601```
602
603```js
604new CleanCSS().minify([
605 {'path/to/file/one': {styles: 'contents of file one'}},
606 {'path/to/file/two': {styles: 'contents of file two'}}
607]);
608```
609
610Passing 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](http://2ality.com/2015/10/property-traversal-order-es6.html) - available since 4.1.0.
611
612Important note - any `@import` rules already present in the hash will be resolved in memory.
613
614## How to process multiple files without concatenating them into one output file?
615
616Since 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.
617
618```js
619var output = new CleanCSS({ batch: true }).minify(['path/to/file/one', 'path/to/file/two']);
620var outputOfFile1 = output['path/to/file/one'].styles // all other fields, like errors, warnings, or stats are there too
621var outputOfFile2 = output['path/to/file/two'].styles
622```
623
624## How to process remote `@import`s correctly?
625
626In 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.:
627
628```js
629var source = '@import url(http://example.com/path/to/remote/styles);';
630new CleanCSS({ inline: ['remote'] }).minify(source, function (error, output) {
631 // output.styles
632});
633```
634
635If you don't provide a callback, then remote `@import`s will be left as is.
636
637## How to apply arbitrary transformations to CSS properties?
638
639Please see [plugins](#plugins).
640
641## How to specify a custom rounding precision?
642
643The level 1 `roundingPrecision` optimization option accept a string with per-unit rounding precision settings, e.g.
644
645```js
646new CleanCSS({
647 level: {
648 1: {
649 roundingPrecision: 'all=3,px=5'
650 }
651 }
652}).minify(source)
653```
654
655which sets all units rounding precision to 3 digits except `px` unit precision of 5 digits.
656
657## How to optimize a stylesheet with custom `rpx` units?
658
659Since `rpx` is a non standard unit (see [#1074](https://github.com/clean-css/clean-css/issues/1074)), it will be dropped by default as an invalid value.
660
661However you can treat `rpx` units as regular ones:
662
663```js
664new CleanCSS({
665 compatibility: {
666 customUnits: {
667 rpx: true
668 }
669 }
670}).minify(source)
671```
672
673## How to keep a CSS fragment intact?
674
675Note: available since 4.2.0.
676
677Wrap the CSS fragment in special comments which instruct clean-css to preserve it, e.g.
678
679```css
680.block-1 {
681 color: red
682}
683/* clean-css ignore:start */
684.block-special {
685 color: transparent
686}
687/* clean-css ignore:end */
688.block-2 {
689 margin: 0
690}
691```
692
693Optimizing this CSS will result in the following output:
694
695```css
696.block-1{color:red}
697.block-special {
698 color: transparent
699}
700.block-2{margin:0}
701```
702
703## How to preserve a comment block?
704
705Use the `/*!` notation instead of the standard one `/*`:
706
707```css
708/*!
709 Important comments included in optimized output.
710*/
711```
712
713## How to rebase relative image URLs?
714
715clean-css will handle it automatically for you in the following cases:
716
717* when full paths to input files are passed in as options;
718* when correct paths are passed in via a hash;
719* when `rebaseTo` is used with any of above two.
720
721## How to work with source maps?
722
723To generate a source map, use `sourceMap: true` option, e.g.:
724
725```js
726new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
727 .minify(source, function (error, output) {
728 // access output.sourceMap for SourceMapGenerator object
729 // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
730});
731```
732
733You can also pass an input source map directly as a 2nd argument to `minify` method:
734
735```js
736new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
737 .minify(source, inputSourceMap, function (error, output) {
738 // access output.sourceMap to access SourceMapGenerator object
739 // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
740});
741```
742
743or even multiple input source maps at once:
744
745```js
746new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory }).minify({
747 'path/to/source/1': {
748 styles: '...styles...',
749 sourceMap: '...source-map...'
750 },
751 'path/to/source/2': {
752 styles: '...styles...',
753 sourceMap: '...source-map...'
754 }
755}, function (error, output) {
756 // access output.sourceMap as above
757});
758```
759
760## How to apply level 1 & 2 optimizations at the same time?
761
762Using the hash configuration specifying both optimization levels, e.g.
763
764```js
765new CleanCSS({
766 level: {
767 1: {
768 all: true,
769 normalizeUrls: false
770 },
771 2: {
772 restructureRules: true
773 }
774 }
775})
776```
777
778will apply level 1 optimizations, except url normalization, and default level 2 optimizations with rule restructuring.
779
780## What level 2 optimizations do?
781
782All level 2 optimizations are dispatched [here](https://github.com/clean-css/clean-css/blob/master/lib/optimizer/level-2/optimize.js#L67), and this is what they do:
783
784* `recursivelyOptimizeBlocks` - does all the following operations on a nested block, like `@media` or `@keyframe`;
785* `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;
786* `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;
787* `mergeAdjacent` - merges adjacent rulesets with the same selector or rules;
788* `reduceNonAdjacent` - identifies which properties are overridden in same-selector non-adjacent rulesets, and removes them;
789* `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;
790* `mergeNonAdjacentByBody` - same as the one above but for same-selector non-adjacent rulesets;
791* `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}`;
792* `removeDuplicateFontAtRules` - removes duplicated `@font-face` rules;
793* `removeDuplicateMediaQueries` - removes duplicated `@media` nested blocks;
794* `mergeMediaQueries` - merges non-adjacent `@media` at-rules by the same rules as `mergeNonAdjacentBy*` above;
795
796## What errors and warnings are?
797
798If 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.
799
800Example: Minify invalid CSS, resulting in two warnings:
801
802```js
803const CleanCSS = require("clean-css");
804
805const output = new CleanCSS().minify(`
806
807 a {
808 -notarealproperty-: 5px;
809 color:
810 }
811 div {
812 margin: 5px
813 }
814
815`);
816
817console.log(output);
818
819// Log:
820{
821 styles: 'div{margin:5px}',
822 stats: {
823 efficiency: 0.8695652173913043,
824 minifiedSize: 15,
825 originalSize: 115,
826 timeSpent: 1
827 },
828 errors: [],
829 inlinedStylesheets: [],
830 warnings: [
831 "Invalid property name '-notarealproperty-' at 4:8. Ignoring.",
832 "Empty property 'color' at 5:8. Ignoring."
833 ]
834}
835```
836
837Example: Minify invalid CSS, resulting in one error:
838
839```js
840const CleanCSS = require("clean-css");
841
842const output = new CleanCSS().minify(`
843
844 @import "idontexist.css";
845 a {
846 color: blue;
847 }
848 div {
849 margin: 5px
850 }
851
852`);
853
854console.log(output);
855
856// Log:
857{
858 styles: 'a{color:#00f}div{margin:5px}',
859 stats: {
860 efficiency: 0.7627118644067796,
861 minifiedSize: 28,
862 originalSize: 118,
863 timeSpent: 2
864 },
865 errors: [
866 'Ignoring local @import of "idontexist.css" as resource is missing.'
867 ],
868 inlinedStylesheets: [],
869 warnings: []
870}
871```
872## Clean-css for Gulp
873An example of how you can include clean-css in gulp
874```js
875const { src, dest, series } = require('gulp');
876const CleanCSS = require('clean-css');
877const concat = require('gulp-concat');
878
879function css() {
880 const options = {
881 compatibility: '*', // (default) - Internet Explorer 10+ compatibility mode
882 inline: ['all'], // enables all inlining, same as ['local', 'remote']
883 level: 2 // Optimization levels. The level option can be either 0, 1 (default), or 2, e.g.
884 // Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
885 };
886
887 return src('app/**/*.css')
888 .pipe(concat('style.min.css'))
889 .on('data', function(file) {
890 const buferFile = new CleanCSS(options).minify(file.contents)
891 return file.contents = Buffer.from(buferFile.styles)
892 })
893 .pipe(dest('build'))
894}
895exports.css = series(css)
896```
897
898## How to use clean-css with build tools?
899
900There is a number of 3rd party plugins to popular build tools:
901
902* [Broccoli](https://github.com/broccolijs/broccoli#broccoli): [broccoli-clean-css](https://github.com/shinnn/broccoli-clean-css)
903* [Brunch](http://brunch.io/): [clean-css-brunch](https://github.com/brunch/clean-css-brunch)
904* [Grunt](http://gruntjs.com): [grunt-contrib-cssmin](https://github.com/gruntjs/grunt-contrib-cssmin)
905* [Gulp](http://gulpjs.com/): [gulp-clean-css](https://github.com/scniro/gulp-clean-css)
906* [Gulp](http://gulpjs.com/): [using vinyl-map as a wrapper - courtesy of @sogko](https://github.com/clean-css/clean-css/issues/342)
907* [component-builder2](https://github.com/component/builder2.js): [builder-clean-css](https://github.com/poying/builder-clean-css)
908* [Metalsmith](http://metalsmith.io): [metalsmith-clean-css](https://github.com/aymericbeaumet/metalsmith-clean-css)
909* [Lasso](https://github.com/lasso-js/lasso): [lasso-clean-css](https://github.com/yomed/lasso-clean-css)
910* [Start](https://github.com/start-runner/start): [start-clean-css](https://github.com/start-runner/clean-css)
911
912## How to use clean-css from web browser?
913
914* https://clean-css.github.io/ (official web interface)
915* http://refresh-sf.com/
916* http://adamburgess.github.io/clean-css-online/
917
918# Contributing
919
920See [CONTRIBUTING.md](https://github.com/clean-css/clean-css/blob/master/CONTRIBUTING.md).
921
922## How to get started?
923
924First clone the sources:
925
926```bash
927git clone git@github.com:clean-css/clean-css.git
928```
929
930then install dependencies:
931
932```bash
933cd clean-css
934npm install
935```
936
937then use any of the following commands to verify your copy:
938
939```bash
940npm run bench # for clean-css benchmarks (see [test/bench.js](https://github.com/clean-css/clean-css/blob/master/test/bench.js) for details)
941npm run browserify # to create the browser-ready clean-css version
942npm run check # to lint JS sources with [JSHint](https://github.com/jshint/jshint/)
943npm test # to run all tests
944```
945
946# Acknowledgments
947
948Sorted alphabetically by GitHub handle:
949
950* [@abarre](https://github.com/abarre) (Anthony Barre) for improvements to `@import` processing;
951* [@alexlamsl](https://github.com/alexlamsl) (Alex Lam S.L.) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
952* [@altschuler](https://github.com/altschuler) (Simon Altschuler) for fixing `@import` processing inside comments;
953* [@ben-eb](https://github.com/ben-eb) (Ben Briggs) for sharing ideas about CSS optimizations;
954* [@davisjam](https://github.com/davisjam) (Jamie Davis) for disclosing ReDOS vulnerabilities;
955* [@facelessuser](https://github.com/facelessuser) (Isaac) for pointing out a flaw in clean-css' stateless mode;
956* [@grandrath](https://github.com/grandrath) (Martin Grandrath) for improving `minify` method source traversal in ES6;
957* [@jmalonzo](https://github.com/jmalonzo) (Jan Michael Alonzo) for a patch removing node.js' old `sys` package;
958* [@lukeapage](https://github.com/lukeapage) (Luke Page) for suggestions and testing the source maps feature;
959 Plus everyone else involved in [#125](https://github.com/clean-css/clean-css/issues/125) for pushing it forward;
960* [@madwizard-thomas](https://github.com/madwizard-thomas) for sharing ideas about `@import` inlining and URL rebasing.
961* [@ngyikp](https://github.com/ngyikp) (Ng Yik Phang) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
962* [@wagenet](https://github.com/wagenet) (Peter Wagenet) for suggesting improvements to `@import` inlining behavior;
963* [@venemo](https://github.com/venemo) (Timur Kristóf) for an outstanding contribution of advanced property optimizer for 2.2 release;
964* [@vvo](https://github.com/vvo) (Vincent Voyer) for a patch with better empty element regex and for inspiring us to do many performance improvements in 0.4 release;
965* [@xhmikosr](https://github.com/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.
966
967# License
968
969clean-css is released under the [MIT License](https://github.com/clean-css/clean-css/blob/master/LICENSE).