PostCSS 插件系统 #

PostCSS 的核心是一个插件系统,所有功能都通过插件实现。理解插件系统是掌握 PostCSS 的关键。

插件工作原理 #

处理流程 #

text
┌─────────────────────────────────────────────────────────────┐
│                     PostCSS 处理流程                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  CSS 源码                                                   │
│     │                                                       │
│     ▼                                                       │
│  ┌──────────┐                                               │
│  │  Parser  │  ─── 解析 CSS 为 AST                          │
│  └────┬─────┘                                               │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────┐                                               │
│  │ Plugin 1 │  ─── 处理 AST(如 Autoprefixer)              │
│  └────┬─────┘                                               │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────┐                                               │
│  │ Plugin 2 │  ─── 处理 AST(如 cssnano)                   │
│  └────┬─────┘                                               │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────┐                                               │
│  │Plugin N  │  ─── 更多插件...                              │
│  └────┬─────┘                                               │
│       │                                                     │
│       ▼                                                     │
│  ┌────────────┐                                             │
│  │Stringifier │  ─── 将 AST 转换回 CSS                      │
│  └─────┬──────┘                                             │
│        │                                                    │
│        ▼                                                    │
│  CSS 输出                                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

插件访问 AST #

每个插件可以访问和修改 AST:

javascript
// 插件结构
const plugin = () => {
  return {
    postcssPlugin: 'my-plugin',
    
    // 访问整个 AST
    Once(root) {
      // 在所有节点处理前执行一次
    },
    
    // 访问特定节点类型
    Rule(rule) {
      // 处理每个规则
    },
    
    Declaration(decl) {
      // 处理每个声明
    },
    
    AtRule(atRule) {
      // 处理每个 @ 规则
    },
    
    Comment(comment) {
      // 处理每个注释
    }
  }
}
plugin.postcss = true

插件加载顺序 #

顺序的重要性 #

插件按配置顺序依次执行:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    // 1. 首先处理导入
    require('postcss-import'),
    
    // 2. 然后处理嵌套
    require('postcss-nested'),
    
    // 3. 接着处理变量
    require('postcss-simple-vars'),
    
    // 4. 添加浏览器前缀
    require('autoprefixer'),
    
    // 5. 最后压缩(必须在最后)
    require('cssnano')
  ]
}

推荐顺序 #

text
1. 导入处理
   └── postcss-import

2. 语法扩展
   ├── postcss-nested
   ├── postcss-simple-vars
   ├── postcss-mixins
   └── postcss-functions

3. 未来特性
   └── postcss-preset-env

4. 兼容性处理
   └── autoprefixer

5. 优化压缩
   └── cssnano

错误顺序示例 #

javascript
// ❌ 错误:cssnano 在前会导致其他插件无法正常工作
module.exports = {
  plugins: [
    require('cssnano'),        // 压缩后无法处理嵌套
    require('postcss-nested'), // 无法正常工作
    require('autoprefixer')
  ]
}

// ✅ 正确:cssnano 在最后
module.exports = {
  plugins: [
    require('postcss-nested'),
    require('autoprefixer'),
    require('cssnano')         // 最后压缩
  ]
}

插件配置方式 #

数组配置 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('cssnano')
  ]
}

对象配置 #

javascript
// postcss.config.js
module.exports = {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: ['> 1%']
    },
    cssnano: {
      preset: 'default'
    }
  }
}

带参数配置 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')({
      overrideBrowserslist: ['> 1%', 'last 2 versions'],
      grid: true
    }),
    require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true }
      }]
    })
  ]
}

条件配置 #

javascript
// postcss.config.js
const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
  plugins: [
    require('autoprefixer'),
    // 只在生产环境压缩
    isProduction && require('cssnano')({
      preset: 'default'
    })
  ].filter(Boolean)  // 过滤掉 false 值
}

函数式配置 #

javascript
// postcss.config.js
module.exports = (ctx) => {
  return {
    plugins: [
      require('autoprefixer')({
        overrideBrowserslist: ctx.env === 'production'
          ? ['> 1%', 'last 2 versions']
          : ['last 1 chrome version']
      }),
      ctx.env === 'production' && require('cssnano')
    ].filter(Boolean)
  }
}

插件分类 #

按功能分类 #

text
PostCSS 插件分类:

├── 1. 预处理功能
│   ├── postcss-import        # @import 处理
│   ├── postcss-nested        # 嵌套语法
│   ├── postcss-simple-vars   # 变量支持
│   ├── postcss-mixins        # Mixin 支持
│   └── postcss-functions     # 自定义函数
│
├── 2. 兼容性处理
│   ├── autoprefixer          # 自动前缀
│   ├── postcss-preset-env    # 未来特性
│   └── postcss-color-hex-alpha # 颜色处理
│
├── 3. 代码优化
│   ├── cssnano               # CSS 压缩
│   ├── postcss-discard-comments # 删除注释
│   ├── postcss-merge-rules   # 合并规则
│   └── postcss-normalize     # 标准化
│
├── 4. 代码检查
│   ├── stylelint             # CSS Lint
│   ├── postcss-bem-linter    # BEM 检查
│   └── doiuse                # 兼容性检查
│
├── 5. 特殊功能
│   ├── postcss-pxtorem       # px 转 rem
│   ├── postcss-sprites       # 雪碧图
│   ├── rtlcss                # RTL 支持
│   └── postcss-write-svg     # SVG 内联
│
└── 6. 框架/预设
    ├── tailwindcss           # Tailwind CSS
    ├── postcss-cssnext       # CSS Next
    └── precss                # 类 Sass 语法

按处理阶段分类 #

阶段 插件示例 说明
解析前 postcss-import 处理导入,合并文件
语法转换 postcss-nested 转换语法扩展
功能增强 postcss-mixins 添加编程特性
兼容处理 autoprefixer 添加浏览器前缀
优化压缩 cssnano 压缩和优化

常用插件详解 #

postcss-import #

处理 CSS 中的 @import 规则:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import')({
      path: ['src/styles'],  // 导入路径
      plugins: []            // 对导入文件应用的插件
    })
  ]
}
css
/* 输入 */
@import 'variables.css';
@import 'mixins.css';

.button {
  color: var(--primary);
}

/* 输出(variables.css 和 mixins.css 内容被内联) */
:root {
  --primary: #007bff;
}

.button {
  color: var(--primary);
}

postcss-nested #

支持嵌套语法:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-nested')
  ]
}
css
/* 输入 */
.button {
  color: blue;
  
  &:hover {
    color: darkblue;
  }
  
  .icon {
    margin-right: 8px;
  }
}

/* 输出 */
.button {
  color: blue;
}

.button:hover {
  color: darkblue;
}

.button .icon {
  margin-right: 8px;
}

postcss-simple-vars #

支持变量:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-simple-vars')({
      variables: {
        primary: '#007bff',
        secondary: '#6c757d'
      }
    })
  ]
}
css
/* 输入 */
$primary: #007bff;

.button {
  color: $primary;
}

/* 输出 */
.button {
  color: #007bff;
}

postcss-mixins #

支持 Mixin:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-mixins')({
      mixins: {
        clearfix: {
          '&::after': {
            content: '""',
            display: 'table',
            clear: 'both'
          }
        }
      }
    })
  ]
}
css
/* 输入 */
@define-mixin button $color {
  background: $color;
  padding: 10px 20px;
  border-radius: 4px;
}

.primary {
  @mixin button blue;
}

/* 输出 */
.primary {
  background: blue;
  padding: 10px 20px;
  border-radius: 4px;
}

postcss-preset-env #

使用未来 CSS 特性:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-preset-env')({
      stage: 2,  // 0-4,数字越小越稳定
      features: {
        'nesting-rules': true,
        'custom-properties': true
      }
    })
  ]
}
css
/* 输入 */
:root {
  --primary: #007bff;
}

.button {
  color: var(--primary);
  
  &:hover {
    color: color(var(--primary) blackness(+20%));
  }
}

/* 输出 */
:root {
  --primary: #007bff;
}

.button {
  color: var(--primary);
}

.button:hover {
  color: rgb(0, 94.8, 191);
}

cssnano #

CSS 压缩优化:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
        normalizeWhitespace: true,
        colormin: true,
        reduceIdents: false
      }]
    })
  ]
}
css
/* 输入 */
.container {
  margin: 10px 10px 10px 10px;
  padding: 0px;
}

.button {
  color: #ff0000;
}

/* 输出 */
.container{margin:10px;padding:0}.button{color:red}

插件预设 #

使用预设 #

预设是一组预配置的插件:

javascript
// postcss.config.js
module.exports = {
  plugins: [
    // 使用预设
    require('postcss-preset-env')({
      stage: 2
    }),
    
    // 可以添加更多插件
    require('cssnano')
  ]
}

创建自定义预设 #

javascript
// my-postcss-preset.js
const autoprefixer = require('autoprefixer')
const cssnano = require('cssnano')
const postcssNested = require('postcss-nested')

module.exports = (options = {}) => {
  const plugins = [
    postcssNested,
    autoprefixer(options.autoprefixer || {})
  ]
  
  if (options.minify) {
    plugins.push(cssnano({ preset: 'default' }))
  }
  
  return plugins
}
javascript
// postcss.config.js
const myPreset = require('./my-postcss-preset')

module.exports = {
  plugins: myPreset({
    minify: process.env.NODE_ENV === 'production'
  })
}

插件开发基础 #

简单插件 #

javascript
const postcss = require('postcss')

const myPlugin = postcss.plugin('my-plugin', (options = {}) => {
  return root => {
    root.walkDecls('color', decl => {
      if (decl.value === 'red') {
        decl.value = options.color || 'blue'
      }
    })
  }
})

module.exports = myPlugin

使用新 API(PostCSS 8+) #

javascript
const plugin = () => {
  return {
    postcssPlugin: 'my-plugin',
    Declaration(decl) {
      if (decl.prop === 'color' && decl.value === 'red') {
        decl.value = 'blue'
      }
    }
  }
}
plugin.postcss = true

module.exports = plugin

插件调试 #

查看插件执行 #

javascript
const postcss = require('postcss')
const autoprefixer = require('autoprefixer')

const css = '.button { display: flex; }'

const result = await postcss([autoprefixer])
  .process(css, { from: undefined })

// 查看消息
result.messages.forEach(msg => {
  console.log(msg.type, msg.plugin, msg.text)
})

插件性能分析 #

javascript
const postcss = require('postcss')

const css = '/* 你的 CSS */'

console.time('postcss')

const result = await postcss([
  require('postcss-import'),
  require('postcss-nested'),
  require('autoprefixer'),
  require('cssnano')
]).process(css, { from: undefined })

console.timeEnd('postcss')
console.log(result.css)

插件生态 #

查找插件 #

插件质量判断 #

指标 说明
周下载量 越高越好
GitHub Stars 社区认可度
更新频率 是否积极维护
文档质量 是否有清晰文档
TypeScript 支持 类型定义

下一步 #

现在你已经深入了解了 PostCSS 插件系统,接下来学习 常用插件 掌握更多实用插件!

最后更新:2026-03-28