PostCSS 原理与工程实践

PostCSS 是前端工程化里处理 CSS 的重要工具。它本质不是新的样式语言,而是一套基于抽象语法树转换 CSS 的 JavaScript 工具平台。

PostCSS 是什么?

PostCSS 是一套利用 JavaScript 工具与插件转换 CSS 代码的工具平台。

PostCSS 不等同于 Sass、Less 这类 CSS 预处理器,它更接近 webpack,本身不提供样式语法扩展,依靠丰富插件生态完成 CSS 的编译、语法检查、自动补前缀等各类处理,由 Evil Martians 团队开发维护。

PostCSS 的核心工作流程十分清晰:

  • 将 CSS 源码解析为抽象语法树(Abstract Syntax Tree,AST),把 CSS 文本转为 JavaScript 可操作的数据结构;
  • 将 AST 交给各个插件执行修改操作;
  • 将处理完成的 AST 重新转回 CSS 文本输出。

插件可以基于 AST 完成非常多能力:实现变量、混入(mixin)、自动补充浏览器厂商前缀、把未来标准的 CSS 语法转译为兼容现有浏览器的样式代码。PostCSS 的核心能力来自它的插件体系,社区已经拥有两百多个功能不同的插件,开发者也可以按需编写自定义插件。

PostCSS 本体只承担两件核心工作:

  • 把 CSS 解析成 JavaScript 可操作的 AST;
  • 调度插件处理 AST,生成最终 CSS 结果。

因此不能简单将 PostCSS 归类为 CSS 预处理工具或者后处理工具,它同时可以完成传统意义上预处理、后处理两类工作。

为什么选择 PostCSS?

在前端工程化体系中,Sass、Less、Stylus 这类 CSS 预处理器被广泛使用。预处理器提供原生 CSS 不具备的高级语法,以此提升样式代码的可读性和可维护性。

社区主流预处理器如下:

  • Sass:2007 年诞生,历史最久、生态成熟,最初依赖 Ruby,后续演化出完全兼容原生 CSS 的 SCSS 语法。
  • Less:2009 年诞生,语法贴近原生 CSS,上手门槛低,Bootstrap 底层便基于 Less,可编程能力弱于 Sass。
  • Stylus:2010 年出自 Node.js 社区,语法灵活,适合构建动态 CSS。

PostCSS 的核心优势:

  • 模块化按需选用能力:不需要全套语法,只安装项目实际需要的插件;
  • 庞大的插件生态:两百多款社区插件覆盖绝大多数 CSS 处理场景;
  • 性能优异,官方基准测试显示处理速度可达传统预处理器的 3 倍以上;
  • 支持自定义插件开发,可以根据业务场景编写专属 CSS 转换逻辑;
  • 兼容原生 CSS,可以和 Less、Sass 协同工作,不需要强制切换样式语法;
  • 和主流构建工具无缝集成,例如 webpack、gulp、CodePen;
  • 完善的 Source Map 支持,便于调试编译之后的样式代码。

一句话总结 PostCSS:传统 CSS 预处理器可以实现的效果,PostCSS 借助插件大多都可以完成,并且更加灵活可控。

PostCSS 的使用

PostCSS 的语法扩展全部来自插件,你可以按需安装嵌套、变量、自动前缀等能力,不必学习全新的样式语言,可以直接书写标准 CSS。

插件资源可以查阅官方中文插件列表,或者使用 postcss.parts 进行检索,也可以阅读官方文档开发自定义插件。

安装与配置方式

常见配置方式,优先级从高到低排列:

  • webpack.config.js
  • postcss.config.js.postcssrc.js
  • .postcssrc
  • package.jsonpostcss 字段

webpack.config.jspostcss-loader 选项内直接配置:

{
  test: /\.css$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        ident: 'postcss',
        plugins: (loader) => [
          require('postcss-import')({ root: loader.resourcePath }),
          require('postcss-preset-env')(),
          require('cssnano')()
        ]
      }
    }
  ]
}

独立配置文件 postcss.config.js.postcssrc.js(推荐):

module.exports = ({ file, options, env }) => ({
  parser: file.extname === '.sss' ? 'sugarss' : false,
  plugins: {
    'autoprefixer': {},
    'postcss-import': { root: file.dirname },
    'postcss-preset-env': options['postcss-preset-env'] ? options['postcss-preset-env'] : false,
    'cssnano': env === 'production' ? options.cssnano : false
  }
})

JSON 格式配置文件 .postcssrc

{
  "plugins": {
    "postcss-plugin": {}
  }
}

写在 package.jsonpostcss 字段(优先级最低):

{
  "postcss": {
    "plugins": {
      "postcss-plugin": {}
    }
  }
}

基于 webpack 搭建最小测试项目

项目借助 postcss-loader 在 webpack 流程中接入 PostCSS。以下示例基于 webpack 4 与 postcss-loader 3。

安装依赖:

npm i webpack@4 webpack-cli@3 -D
npm i css-loader@4 postcss-loader@3 mini-css-extract-plugin@0.10 -D

项目目录结构:

- build
  - webpack.postcss.config.js
- src
  - index.css
  - index.js
- package.json
- postcss.config.js

webpack 配置文件 build/webpack.postcss.config.js

const Path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const webpackConfig = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: Path.resolve(__dirname, '../dist'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'index.css',
      chunkFilename: 'chunkIndex.css',
    })
  ]
}
module.exports = webpackConfig

注意MiniCssExtractPlugin 不能与 style-loader 同时使用。用 CLI(webpack --config)即可;若改用 Node API 调用 webpack(config, callback),必须传入回调并处理 err,空回调会把编译失败吞掉。

入口 src/index.js

import './index.css'

样式文件 src/index.css

.hello {
  box-sizing: border-box;
}

postcss 配置 postcss.config.js

module.exports = ({ file, options, env }) => ({
  plugins: {}
})

在 package.json 添加执行脚本:

{
  "scripts": {
    "postcss": "webpack --config build/webpack.postcss.config.js"
  }
}

在项目根目录,在终端执行命令:

npm run postcss

常用插件

Autoprefixer

Autoprefixer 根据 Can I Use 的浏览器兼容数据,自动为 CSS 属性补充厂商前缀。

npm i autoprefixer -D

目标浏览器范围依靠 Browserslist 配置,支持三种配置位置:

  • postcss.config.jsoverrideBrowserslist
  • package.jsonbrowserslist
  • 项目根目录 .browserslistrc

配置 postcss.config.js

module.exports = ({ file }) => ({
  plugins: {
    "autoprefixer": {
      "overrideBrowserslist": [
        "> 0.1%",
        "last 2 versions",
        "Android >= 3.2",
        "Firefox >= 20",
        "iOS >= 7",
        "chrome > 20"
      ]
    }
  }
})

输入:

.autoprefixer {
  box-sizing: border-box;
}

输出:

.autoprefixer {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

postcss-nesting、postcss-nested

两个插件都实现 CSS 嵌套语法,但遵循两套不同规范:

  • postcss-nesting:遵循 W3C 标准嵌套选择器,每一层嵌套必须显式写 &
  • postcss-nested:模仿 Sass 的嵌套写法,大部分场景可以省略 &

推荐优先使用 postcss-nesting,贴近标准草案。

npm i postcss-nesting -D
# npm i postcss-nested -D

配置 postcss.config.js

module.exports = ({ file }) => ({
  plugins: {
    "postcss-nesting": {}
  }
})

输入:

.postcss_nesting {
  & sub_class {
    width: 100%;
  }
  & a {
    color: red;
  }
}

输出:

.postcss_nesting sub_class {
  width: 100%;
}
.postcss_nesting a {
  color: red;
}

postcss-import

允许 CSS 文件中使用 @import 将外部样式文件内联合并,避免浏览器多次请求样式文件。

npm i postcss-import -D

配置 postcss.config.js

module.exports = ({ file }) => ({
  plugins: {
    "postcss-import": {}
  }
})
@import './import.css';

编译后会把 import.css 的内容直接合并进输出 CSS。

postcss-preset-env

postcss-preset-env 相当于 CSS 的 Babel,基于 cssdb,将现代 CSS 语法转译为兼容旧浏览器的代码,会根据目标浏览器自动启用对应语法转换。

备注:该插件内置 Autoprefixer、postcss-nesting 等能力,项目开启它之后一般无需重复引入上述插件。

npm i postcss-preset-env -D

配置 postcss.config.js

module.exports = {
  plugins: {
    "postcss-preset-env": {
      features: {
        "custom-properties": {
          preserve: false,
          variables: {}
        },
        "nesting-rules": true
      }
    }
  }
}

cssnano

生产环境 CSS 压缩优化插件,不止简单去除空格换行,还会做属性合并、规则合并等多项优化,用来减小最终 CSS 体积。

npm i cssnano -D

配置 postcss.config.js

module.exports = {
  plugins: {
    "cssnano": {
      preset: ["default", {
        // 禁止重命名自定义动画 keyframes 名称
        reduceIdents: false,
        // 关闭 z-index 值的自动重排优化
        zindex: false
      }]
    }
  }
}

postcss-apply

借助 @apply,可以复用定义在 CSS 自定义属性集内的一组样式。

注意:该语法不属于正式 Web 标准,浏览器不再计划原生支持该特性,仅作为编译期能力使用。需要搭配 postcss-import 一起工作。

npm i postcss-apply -D

配置 postcss.config.js

module.exports = {
  plugins: {
    "postcss-import": {},
    "postcss-apply": {}
  }
}
/* apply.css */
:root {
    --no-wrap: {
        width: 100%;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}
/* index.css */
@import './apply.css';
.apply {
  color: green;
  @apply --no-wrap;
}

输出:

.apply {
  color: green;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

postcss-mixins

提供混入(mixin)能力,支持定义可复用样式片段并传入参数。

npm i postcss-mixins -D

配置 postcss.config.js

module.exports = ({ file }) => ({
  plugins: {
    "postcss-mixins": {},
  }
})

输入:

/* index.css */
@define-mixin icon $name, $color: blue {
  .icon.is-$(name) {
    color: $color;
  }
  .icon.is-$(name):hover {
    color: white;
    background: $color;
  }
}

@mixin icon twitter {
  background: url(twt.png);
}

输出:

.icon.is-twitter {
  color: blue;
}
.icon.is-twitter:hover {
  color: white;
  background: blue;
}
.icon.is-twitter {
  background: url(twt.png);
}

postcss-px2rem-exclude

将 px 单位自动转换为 rem,同时支持配置排除目录,不转换某些文件。

npm i postcss-px2rem-exclude -D

配置 postcss.config.js

module.exports = {
  "plugins": {
    "postcss-px2rem-exclude": {
      remUnit: 75,
      exclude: /node_modules|folder_name/i
    }
  }
}

输入:

.px2rem {
  width: 100px;
  font-size: 30px;
}

输出:

.px2rem {
  width: 1.333333rem;
  font-size: 0.4rem;
}

参考文档

PostCSS

PostCSS 中文

Browserslist

browserslist.dev

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-19 22:47:53

results matching ""

    No results matching ""