Skip to content

PostCSS Plugins — Complete Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about PostCSS Plugins. We cover key concepts, practical examples, and best practices to help you master this topic.

PostCSS plugins extend CSS processing with autoprefixing, linting, Minification, image inlining, custom transformations, and more for production optimization.

What You'll Learn

  • Essential PostCSS plugins
  • Stylelint for CSS linting
  • CSSNano for minification
  • PostCSS-import for CSS organization
  • PostCSS-mixins (preprocessor-like features)
  • Custom plugin development

Why It Matters

  • The PostCSS plugin ecosystem is vast
  • Each plugin solves a specific CSS problem
  • Composable pipeline for custom workflows
  • Many plugins complement preprocessors

Real-World Use

  • A CI pipeline runs Stylelint for CSS quality
  • A production build uses CSSNano for minimal output
  • A design system uses postcss-import for file organization
  • A team uses postcss-inline-svg for icon optimization
flowchart LR
  A[PostCSS Plugins] --> B[Quality]
  A --> C[Optimization]
  A --> D[Convenience]
  A --> E[Future CSS]
  B --> F[Stylelint]
  C --> G[CSSNano]
  C --> H[postcss-inline-svg]
  D --> I[postcss-import]
  D --> J[postcss-mixins]
  E --> K[postcss-preset-env]

Essential Plugins

Code Example: Stylelint with PostCSS

// postcss.config.js with Stylelint
module.exports = {
    plugins: [
        require('stylelint')({
            config: {
                rules: {
                    'color-no-invalid-hex': true,
                    'declaration-no-important': true,
                    'selector-max-specificity': '0,3,0',
                    'max-nesting-depth': 3,
                    'unit-allowed-list': ['px', 'rem', '%', 'em', 'vw', 'vh'],
                    'at-rule-no-unknown': true,
                    'block-no-empty': true,
                    'no-duplicate-selectors': true,
                    'font-family-no-duplicate-names': true,
                    'comment-no-empty': true
                }
            }
        }),
        require('postcss-preset-env')({ stage: 2 }),
        require('autoprefixer')
    ]
};
# Also run Stylelint standalone
npm install --save-dev stylelint stylelint-config-standard

# With config file
// .stylelintrc.json
{
    "extends": "stylelint-config-standard",
    "rules": {
        "max-nesting-depth": 3,
        "selector-class-pattern": "^[a-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*(__[a-zA-Z0-9]+)*(--[a-zA-Z0-9]+)*$",
        "unit-allowed-list": ["px", "rem", "em", "%", "vw", "vh", "deg"]
    }
}

Expected output: Stylelint validates CSS against configurable rules during the build. Invalid hex colors, !important usage, excessive nesting depth, and disallowed units are flagged as errors.

Code Example: CSSNano for Minification

// postcss.config.js production
module.exports = {
    plugins: [
        require('autoprefixer'),
        require('cssnano')({
            preset: ['default', {
                discardComments: {
                    removeAll: true
                },
                normalizeWhitespace: true,
                minifyFontValues: true,
                minifyGradients: true,
                mergeLonghand: true,
                discardUnused: {
                    fontFace: true
                }
            }]
        })
    ]
};
/* Input */
.card {
    background-color: #ffffff;
    background-color: var(--bg, #ffffff);
    margin-top: 16px;
    margin-right: 16px;
    margin-bottom: 16px;
    margin-left: 16px;
    font-weight: 400;
    font-style: normal;
    -webkit-transition: all 0.3s ease;
    transition: all 0.3s ease;
}

/* Output (cssnano) */
.card{background-color:#fff;background-color:var(--bg,#fff);margin:16px;font-weight:400;font-style:normal;transition:all .3s ease}

Expected output: CSSNano removes whitespace, shortens hex colors (#ffffff to #fff), merges longhand margin into shorthand, removes redundant font styles, normalizes vendor prefixes, and removes comments.

Code Example: PostCSS-import and PostCSS-mixins

// postcss.config.js
module.exports = {
    plugins: [
        require('postcss-import')({
            path: ['src/css'],  // Resolve paths
            plugins: []          // Additional plugins for imports
        }),
        require('postcss-mixins')({
            mixins: {
                'button-variant': (mixin, bg, color = '#fff') => {
                    return {
                        'background': bg,
                        'color': color,
                        'border': 'none',
                        'border-radius': '4px',
                        'padding': '8px 16px',
                        '&:hover': {
                            'background': `darken(${bg}, 10%)`
                        }
                    };
                },
                'respond-to': (mixin, bp) => {
                    const breakpoints = {
                        'sm': '480px',
                        'md': '768px',
                        'lg': '1024px'
                    };
                    const width = breakpoints[bp] || '768px';
                    return {
                        [`@media (min-width: ${width})`]: {
                            ...mixin.parent
                        }
                    };
                }
            }
        }),
        require('autoprefixer')
    ]
};
/* Input using postcss-import */
/* main.css */
@import 'variables.css';
@import 'components/button.css';
@import 'components/card.css';
/* Input using postcss-mixins */
@define-mixin button-variant $bg, $color: #fff {
    background: $bg;
    color: $color;
    padding: 8px 16px;
    border: none;
    border-radius: 4px;

    &:hover {
        background: color-mod($bg shade(10%));
    }
}

.btn-primary {
    @mixin button-variant #0066CC;
}

.btn-secondary {
    @mixin button-variant #6c757d;
}

Expected output: postcss-import resolves @import statements and combines files. postcss-mixins adds Sass-like mixin functionality to PostCSS, enabling parameterized reusable style blocks.

Code Example: Utility Plugins

// postcss.config.js
module.exports = {
    plugins: [
        // Inline small images as base64
        require('postcss-url')({
            url: 'inline',
            maxSize: 10  // KB - only inline files under 10KB
        }),

        // Inline SVGs as background
        require('postcss-inline-svg')({
            paths: ['src/images/icons']
        }),

        // Add font-display: swap to all @font-face
        require('postcss-font-display')({
            display: 'swap'
        }),

        // Generate rem fallbacks for IE
        require('postcss-pxtorem')({
            rootValue: 16,
            propList: ['*']
        }),

        // Handle CSS logical properties fallback
        require('postcss-logical')(),

        // Focus-within polyfill
        require('postcss-focus-within')(),

        // Reduce calc() expressions
        require('postcss-calc')(),

        // All-in-one
        require('autoprefixer')
    ]
};
/* postcss-inline-svg input */
.element {
    background: svg-load('icon-arrow.svg', fill: #0066CC);
}

/* postcss-font-display input */
@font-face {
    font-family: 'CustomFont';
    src: url('/fonts/custom.woff2');
}

/* Output */
@font-face {
    font-family: 'CustomFont';
    src: url('/fonts/custom.woff2');
    font-display: swap;
}

/* postcss-pxtorem input */
.element {
    padding: 16px;
    font-size: 14px;
}

/* Output */
.element {
    padding: 1rem;
    font-size: 0.875rem;
}

Expected output: Utility plugins handle common transformations: inlining small images, injecting SVG into CSS backgrounds, adding font-display to @font-face, converting px to rem, and handling CSS logical properties.

Common Mistakes

  1. Wrong plugin order — Some plugins must run before others. For example, postcss-import must run before other plugins that modify the code.
  2. Over-minification — CSSNano aggressive presets can break some CSS. Use the default preset unless you test thoroughly.
  3. Not Caching — PostCSS plugins can be slow with many files. Use build tool caching (Webpack cache, Vite cache).
  4. Using too many plugins — Each plugin adds build time. Only use plugins that solve specific problems in your project.
  5. Not configuring browserslist — Many plugins rely on browserslist. Configure it once in package.json.
  6. Ignoring plugin documentation — Each plugin has specific configuration. Read the docs before using.
  7. Plugin conflicts — Two plugins modifying the same property can conflict. Test the plugin combination.

Practice Questions

  1. What does CSSNano do? Minifies and optimizes CSS output (removes whitespace, shortens colors, merges properties, removes comments).
  2. How does postcss-import differ from Sass @import? postcss-import resolves URLs and combines files at the PostCSS level, working with standard CSS @import statements.
  3. What is browserslist and why is it important for PostCSS? A configuration file that defines which browsers to support. Autoprefixer, preset-env, and other plugins use it to determine what transpilations are needed.
  4. Name 3 PostCSS plugins and their purposes. Autoprefixer (vendor prefixes), cssnano (minification), stylelint (linting), postcss-preset-env (future CSS), postcss-import (file concatenation).

FAQ

What is the most popular PostCSS plugin?

Autoprefixer is the most popular. It is used in nearly every PostCSS pipeline for automatic vendor prefix management.

Can I use PostCSS without a preprocessor?

Yes. PostCSS with preset-env, nesting, and mixins plugins can replace many preprocessor features. Many projects use PostCSS alone.

Does PostCSS work with CSS-in-JS?

PostCSS is for CSS files. CSS-in-JS solutions (styled-components, Emotion) have their own preprocessing.

Mini Project

Build a production-ready PostCSS pipeline with 8 plugins: postcss-import (file organization), stylelint (CSS quality), postcss-preset-env (future CSS), autoprefixer (prefixes), postcss-inline-svg (SVG optimization), postcss-font-display (font loading), cssnano (minification), and postcss-reporter (error output). Configure browserslist for 1% market share. Create a CSS file that imports 3 partials, uses nesting, custom properties, inline SVG, and @font-face. Run the pipeline and verify all transformations. Compare the input size to the output size.

What's Next

Continue with Lesson 27: Preprocessor Comparison to compare Sass, Less, Stylus, and PostCSS.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro