A modular minifier, built on top of the PostCSS ecosystem.

  • By null
  • Last update: Sep 17, 2022
  • Comments: 17


cssnano


A modular minifier, built on top of the PostCSS ecosystem.

Backers on Open Collective Sponsors on Open Collective NPM version Build Status codecov Gitter

cssnano is a modern, modular compression tool written on top of the PostCSS ecosystem, which allows us to use a lot of powerful features in order to compact CSS appropriately.

Our preset system allow you to load cssnano in a different configuration depending on your needs; the default preset performs safe transforms, whereas the advanced preset performs more aggressive transforms that are safe only when your site meets the requirements; but regardless of the preset you choose, we handle more than whitespace transforms!

Optimisations range from compressing colors & removing comments, to discarding overridden at-rules, normalising unicode-range descriptors, even mangling gradient parameters for a smaller output value! In addition, where it's made sense for a transform, we've added Browserslist to provide different output depending on the browsers that you support.

For further details check out the website:

You can now try cssnano online!

Contributing

See CONTRIBUTING.md.

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! πŸ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

License

MIT Β© Ben Briggs

Github

https://github.com/cssnano/cssnano

Comments(17)

  • 1

    When will you release version 4?

    It took me a while to figure out that the site with documentation is talking about version 4 as having safe defaults. The instructions just tells to npm install cssnano --save-dev which installs version 3 apparently.

    So two questions:

    1. When will 4 be released?
    2. Where can I find the documentation for 3?

    Thank you for your hard work.

  • 2

    cssDeclarationSorter is not safe when shorthand after longhand property

    Input:

    .bounce {
    	animation-name: bounce;
    	animation: bounce2 1s ease;
    	z-index: 1442;
    }
    

    Output:

    ._bounce_{animation:_bounce2_ 1s ease;animation-name:_bounce_;z-index:1442}
    

    Expected output:

    ._bounce_{animation-name:_bounce_;animation:_bounce2_ 1s ease;z-index:1442}
    

    /cc @evilebottnawi


    Other bug (need add tests):

    Input:

    .class {
      border-radius: 10px;
      border-bottom-left-radius: 0;
    }
    

    Output:

    .class{border-bottom-left-radius:0;border-radius:10px}
    

    Other bug (need also add tests):

    Input:

    border-width: 2px;
    border-style: solid;
    border-top: 0;
    border-left: 0;
    

    Output:

    border-left: 0;
    border-style: solid;
    border-top: 0;
    border-width: 2px;
    
  • 3

    BrowserslistError: Unknown version 67 of android

    Going from 4.0.0-rc.2 to 4.0.0 I get the following error:

    ERROR in ./app.scss (./node_modules/css-loader!./node_modules/postcss-loader/lib!./node_modules/sass-loader/lib/loader.js!./node_modules/import-glob-loader!./src/client/app.scss)
    Module build failed (from ./node_modules/postcss-loader/lib/index.js):
    BrowserslistError: Unknown version 67 of android
        at Function.select (./node_modules/caniuse-api/node_modules/browserslist/index.js:622:17)
        at ./node_modules/caniuse-api/node_modules/browserslist/index.js:151:33
        at Array.reduce (<anonymous>)
        at resolve (./node_modules/caniuse-api/node_modules/browserslist/index.js:132:18)
        at browserslist (./node_modules/caniuse-api/node_modules/browserslist/index.js:224:16)
        at isSupported (./node_modules/caniuse-api/dist/index.js:62:37)
        at ./node_modules/cssnano-preset-default/node_modules/postcss-reduce-initial/dist/index.js:39:60
        at initializePlugin (./node_modules/cssnano/dist/index.js:35:51)
        at <anonymous>
     @ ./app.scss 2:14-215 21:1-42:3 22:19-220
     @ multi webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000 react-hot-loader/patch ./index.jsx ./app.scss
    

    When compiling with webpack. My browerslist config is as follows:

    {
      "browserslist": [
        "last 2 version",
        "> 1%"
      ]
    }
    
  • 4

    stop transform transparent to initial when need support for edge

    tranform

    input[type=range]::-ms-thumb {
      background-color: transparent;
    }
    

    to

    input[type=range]::-ms-thumb {
      background-color: initial;
    }
    

    will cause a bug in Edge causing slider thumb unseenable

  • 5

    Migrate to PostCSS 8 but keep multiple AST traversals

    Per our discussion https://github.com/cssnano/cssnano/pull/961, this should supersede #961 and #954 .

    I’m exposing cssnano as a plugin that returns a processor, per our disccussion on the postcss repository: https://github.com/postcss/postcss/pull/1485

    I think it would be useful to check what the upgrade impact would be on widely used dependents, like:

    • https://github.com/egoist/rollup-plugin-postcss
    • https://github.com/webpack-contrib/css-minimizer-webpack-plugin
  • 6

    Upgrade css declaration sorter

    :wind_chime: A fresh take on PR #580 to resolve issue #535 making css-declaration-sorter safe by adding a new option keepOverrides.

    For now I'm using the GitHub repository to get some feedback on this PR, once it's reviewed I'll publish the changes as a new major version 5.0.

    I do need some help to get all tests working, I did update the snapshots but can't get the integration tests to pass.

  • 7

    chore(docs): update website

    • Remove unsupported stylesheets config
    • update to new React Monaco editor API
    • correct invalid React inline style property
    • get rid of console warning on home page
    • Remove dependency on old Styled Components release
    • Remove example blog posts
  • 8

    Whitespace not removed in some case instances

    Just trying this for the first time. Config is via PostCSS plugin inside a gulp task. No options set and I get weird whitespace included in lots of cases. Here is a tiny snippet:

    background-repeat:no-repeat}.sport_1:before,.sport_31:before,.sport_74:before,.sport_82:before{
        background-position:50% 2px}.sport_2:before,.sport_73:before,.sport_81:before{
        background-position:50% -1081px}.sport_3:before{
        background-position:50% -2109px}.sport_4:before,.sport_85:before{
        background-position:50% -3135px}.sport_5:before,.sport_129:before,.sport_130:before,.sport_131:before,.sport_132:before,.sport_133:before,.sport_134:before,.sport_135:before,.sport_136:before,.sport_137:before,.sport_800:before,.sport_996:before{
        background-position:50% -57px}.sport_6:before{
        background-position:50% -855pt}.sport_7:before{
        background-position:50% -2166px}.sport_8:before{
        background-position:50% -2337px}.sport_9:before{
    

    Expected:

    background-repeat:no-repeat}.sport_1:before,.sport_31:before,.sport_74:before,.sport_82:before{background-position:50% 2px}.sport_2:before,.sport_73:before,.sport_81:before{background-position:50% -1081px}.sport_3:before{background-position:50% -2109px}.sport_4:before,.sport_85:before{background-position:50% -3135px}.sport_5:before,.sport_129:before,.sport_130:before,.sport_131:before,.sport_132:before,.sport_133:before,.sport_134:before,.sport_135:before,.sport_136:before,.sport_137:before,.sport_800:before,.sport_996:before{background-position:50% -57px}.sport_6:before{background-position:50% -855pt}.sport_7:before{background-position:50% -2166px}.sport_8:before{background-position:50% -2337px}.sport_9:before{
    
  • 9

    why async?

    postcss([ cssnano ]).process(styles).css
    // or
    cssnano.process(styles).css;
    
    Error: Use process(css).then(cb) to work with async plugins
    

    I'd much prefer to use postcss synchronously in my current project.

  • 10

    Update more plugins to PostCSS 8

    • [x] postcss-normalize-charset
    • [x] postcss-normalize-display-values
    • [x] postcss-normalize-positions
    • [x] postcss-normalize-repeat-style
    • [x] postcss-normalize-string
    • [x] postcss-normalize-timing-functions
    • [x] postcss-normalize-unicode
    • [x] postcss-normalize-url
    • [x] postcss-normalize-whitespace
    • [x] postcss-ordered-values
    • [x] postcss-reduced-idents
    • [x] postcss-reduced-initial
    • [x] postcss-reduced-transform
    • [x] postcss-svgo
    • [x] postcss-unique-selectors
    • [x] postcss-zindex
    • [x] stylehacks
    • [x] find out why colormin fails
  • 11

    New maintainer requested.

    Hi folks,

    I thought I would have time to maintain this project for Ben but I need to be realistic and admit that I don't have the cycles. I have given npm publish permissions to @ai (except for the postcss-svgo and postcss-zindex packages that I didn't have permissions on, @ben-eb will need to handle those).

    Hopefully, a new primary maintainer can be found and development can proceed apace.

    Chris

  • 12

    [Bug]: Handling of 0% to 0 conversion

    Describe the bug

    height:0% should not be converted to height:0. But in the latest version, it will be converted to 0. For example:

    .test {
        height: 0%;
    }
    

    will be converted to

    .orxMcomC{height:0}
    

    Expected behaviour

    Should keep 0% for height

    Steps to reproduce

    1. Given a height: 0%
    2. Run build
    3. Check the output

    Version

    5.1.13

    Preset

    (no preset)

    Environment

    System:
        OS: macOS 12.5.1
        CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
        Memory: 1.01 GB / 16.00 GB
        Shell: 5.8.1 - /bin/zsh
    

    Package details

    β”œβ”€β”¬ [email protected]
    β”‚ └── [email protected]  deduped
    β”œβ”€β”€ [email protected] 
    β”œβ”€β”€ [email protected] 
    └─┬ [email protected]
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected]  deduped
      β”œβ”€β”€ [email protected] 
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected] 
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected] 
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected] 
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected] 
      └─┬ [email protected]
        └── [email protected]
    

    Additional context

    No response

  • 13

    `u + a` selector is minified to `u+a`

    Describe the bug

    u + a {
      color: green;
    }
    

    becomes :

    u+a{color:green}
    

    Expected behaviour

    I expected cssnano to avoid forming <urange> tokens.

    https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#urange-syntax

    There are likely more error cases.

    Steps to reproduce

    https://cssnano.co/playground/#eyJpbnB1dCI6InUgKyBhe2NvbG9yOmdyZWVufSIsImNvbmZpZyI6ImNzc25hbm8tcHJlc2V0LWRlZmF1bHQifQ==

    Version

    playground version

    Preset

    default

    Environment

    playground
    

    Package details

    playground
    

    Additional context

    No response

  • 14

    [Bug]: postcss-normalize-whitespace less-loader css-var is error

    Describe the bug

    ERROR in ./App.css (./App.css.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./App.css) Module build failed (from ./node_modules/less-loader/dist/cjs.js):

    --my-primary-color: #ee2233
    

    } ^ Unrecognised input. Possibly missing opening '{' Error in /Users/mac-dio/MyCoding/workspace/tinper-next-packages/next-server/tns-app/app-provider/App.css (line 4, column 0) Error:

    --my-primary-color: #ee2233
    

    } ^ Unrecognised input. Possibly missing opening '{' Error in /Users/mac-dio/MyCoding/workspace/tinper-next-packages/next-server/tns-app/app-provider/App.css (line 4, column 0) at Object.lessLoader (/Users/mac-dio/MyCoding/workspace/tinper-next-packages/next-server/tns-app/app-provider/node_modules/less-loader/dist/index.js:74:14) @ ./App.css @ ./App.jsx 13:0-19 @ ./index.js 25:0-28 26:50-53

    ERROR in ./App.css

    Expected behaviour

    postcss-normalize-whitespace line 97

    input :

    :root{ --my-primary-color:#333; } output: :root{--my-primary-color:#333}

    want fix output: :root{--my-primary-color:#333;}

    Steps to reproduce

    https://blog.csdn.net/jiujiuyaokan/article/details/9146941

    Version

    postcss-normalize-whitespace 5.1.1

    Preset

    (no preset)

    Environment

    os
    

    Package details

    [email protected]
    [email protected]
    

    Additional context

    No response

  • 15

    [Bug]: border-color of 'inherit' mistakenly removed

    Describe the bug

    Given the following code:

    div {
      border: 1em solid; 
      border-color: inherit;
      border-top: none;
    }
    

    The entire border-color: inherit; rule will be removed. This is incorrect. Reduced test case: here.

    Given the following code:

    div {
      border: 1em solid; 
      border-color: inherit;
    }
    

    The border-color: inherit; rule will not be removed. This is correct. The default value of a border-color is currentColor which is different from inherit. This is why the rule must be kept. See also: MDN.

    Expected behaviour

    Given the following code:

    div {
      border: 1em solid; 
      border-color: inherit;
      border-top: none;
    }
    

    All 3 of the rules need to be kept as-is.

    Steps to reproduce

    1. Go to this playground link
    2. Click Minimize
    3. See rule border-color: inherit; removed

    Version

    5.0.14

    Preset

    default

    Environment

    System:
        OS: macOS 12.5
        CPU: (10) arm64 Apple M1 Pro
        Memory: 283.16 MB / 16.00 GB
        Shell: 5.8.1 - /bin/zsh
    

    Package details

    └─┬ @netvlies/[email protected]
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected] deduped
      β”œβ”€β”¬ [email protected]
      β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ β”œβ”€β”€ [email protected] deduped
      β”‚ β”‚ β”‚ └─┬ [email protected]
      β”‚ β”‚ β”‚   └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ β”‚ └── [email protected] deduped
      β”‚ β”‚ └── [email protected] deduped
      β”‚ └── [email protected] deduped
      β”œβ”€β”¬ [email protected]
      β”‚ └── [email protected]
      β”œβ”€β”€ [email protected]
      β”œβ”€β”¬ [email protected]
      β”‚ β”œβ”€β”¬ [email protected]
      β”‚ β”‚ └── [email protected]
      β”‚ └── [email protected]
      └─┬ [email protected]
        β”œβ”€β”¬ @stylelint/[email protected]
        β”‚ └── [email protected] deduped
        β”œβ”€β”¬ @stylelint/[email protected]
        β”‚ └── [email protected] deduped
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected] deduped
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected] deduped
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected]
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected]
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected]
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected]
        β”œβ”€β”¬ [email protected]
        β”‚ └── [email protected] deduped
        β”œβ”€β”€ [email protected]
        └─┬ [email protected]
          └── [email protected]
    

    Additional context

    Please note that I have v5.0.14 on my system, which has this bug, but it also happens on the online playground, of which I don't know the version.

  • 16

    [Bug]: mergeRules invalid order of selectors

    Describe the bug

    if mergeRules is enabled, it may result invalid order of selectors

    Expected behaviour

    Order of selectors does not change the behaviour of initial css file

    Steps to reproduce

    source:

    .name {
      font-family: "InterVariable", "Inter", BlinkMacSystemFont, -apple-system, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      font-weight: 400;
      font-size: 18px;
      line-height: 1.5;
      letter-spacing: -0.01em;
      -webkit-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      -moz-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      font-weight: 600;
    }
    .name.small {
      font-family: "InterVariable", "Inter", BlinkMacSystemFont, -apple-system, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      font-weight: 400;
      font-size: 16px;
      line-height: 1.5;
      letter-spacing: -0.01em;
      -webkit-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      -moz-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
      font-weight: 600;
    }
    

    Result with "default" preset (prettified for readability):

    .name {
        -webkit-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        -moz-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        font-size: 18px;
        font-weight: 600
    }
    .name, .name.small {
        font-family: InterVariable, Inter, BlinkMacSystemFont, -apple-system, Segoe UI, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
        font-weight: 400;
        letter-spacing: -.01em;
        line-height: 1.5
    }
    .name.small {
        -webkit-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        -moz-font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        font-feature-settings: "ccmp", "locl", "mark", "kern", "pnum", "cpsp";
        font-size: 16px;
        font-weight: 600
    }
    

    Result causes .name to end up with font-weight: 400, while expected font-weight should be 600. Problem would not appear, if .name, .name-small would appear before .name selector or font-weight would not be consolidated. BTW, not clear for me, why font-feature-settings were not moved.

    Version

    5.1.12

    Preset

    default

    Environment

    Ubuntu 18.04, Bash
    

    Package details

    [email protected]
    

    Additional context

    Can be reproed in cssnano playground.

  • 17

    [Bug]: Cssnano hangs when including `|` character in identifier

    Describe the bug

    Including | at the beginning of a CSS selector results in the cssnano process never terminating. For example minification of:

    | h1 {}
    

    does not terminate.

    Other combinations of selectors with this character work fine: h1 |, |h1, h1|.

    Output from postcss parse:

    Root {
      raws: { semicolon: false, after: '' },
      type: 'root',
      nodes: [
        Rule {
          raws: [Object],
          type: 'rule',
          nodes: [Array],
          parent: [Circular *1],
          source: [Object],
          selector: '| body',
          [Symbol(isClean)]: false,
          [Symbol(my)]: true
        }
      ],
      source: {
        input: Input {
          css: '| body { margin:0; }',
          hasBOM: false,
          id: '<input css -2Oudu>',
          [Symbol(fromOffsetCache)]: [Array]
        },
        start: { offset: 0, line: 1, column: 1 }
      },
      [Symbol(isClean)]: false,
      [Symbol(my)]: true
    }
    

    Expected behaviour

    cssnano should exit on this input.

    Steps to reproduce

    Problem can be validated via https://cssnano.co/playground/

    For cli usage:

    postcss test.css --use cssnano --no-map
    

    Version

    5.1.11

    Preset

    (no preset)

    Environment

    System:
        OS: macOS 11.6.4
        CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
        Memory: 50.88 MB / 32.00 GB
        Shell: 5.8 - /bin/zsh
    

    Package details

    └── [email protected]
    

    Additional context

    No response