技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTCSS

什么是 PostCSS?如何使用插件自动化 CSS 任务

所属馆藏
CSS
文件格式
Markdown
原始路径
CSS/19-什么是 PostCSS?如何使用插件自动化 CSS 任务
本文目录11 个章节
  1. 什么是 PostCSS?
  2. PostCSS 的特点和优势
  3. 常用 PostCSS 插件
  4. 如何设置 PostCSS
  5. 使用 PostCSS CLI
  6. 通过 package.json 脚本运行
  7. 通过配置文件运行 PostCSS
  8. 使用任务运行器或模块打包器
  9. 什么时候使用 PostCSS?
  10. 总结
  11. 参考资料

什么是 PostCSS?如何使用插件自动化 CSS 任务

Category(分类): CSS Status: 未知

本文整理自早期 PostCSS 学习资料,保留原文对常用插件、CLI、配置文件和任务运行器的介绍,并修正插件定位、现代 CSS 嵌套、Autoprefixer 输出、Stylelint 配置和安装命令等问题。

什么是 PostCSS?

PostCSS 是一个基于 JavaScript 的 CSS 处理工具。它可以:

  1. 将 CSS 源码解析为抽象语法树(AST);
  2. 按顺序运行一个或多个插件;
  3. 由插件分析、转换或检查 AST;
  4. 将处理后的 AST 输出为 CSS,并在需要时生成 source map。

PostCSS 本身主要负责解析、插件调度和输出,不会自动提供变量、嵌套、混合或浏览器前缀。具体能力来自插件,例如:

  • postcss-import:在构建阶段内联 CSS 文件;
  • Autoprefixer:根据目标浏览器补充必要的厂商前缀;
  • postcss-preset-env:根据目标浏览器转换部分现代 CSS;
  • postcss-nested:处理嵌套规则;
  • postcss-mixins:提供 Mixin 语法;
  • Stylelint:检查 CSS 代码,但通常作为独立工具运行;
  • Cssnano:压缩生产环境的 CSS。

因此,PostCSS 既不能简单称为预处理器,也不能简单称为后处理器。它是一套 CSS 处理基础设施,既可以在预处理阶段使用,也可以在兼容性转换、代码检查和压缩阶段使用。

可以把 PostCSS 与 Babel 作类比:两者都可以解析源码、运行插件并输出转换后的代码,但 PostCSS 专门处理 CSS 及相关语法。

PostCSS 能否替代 Sass、Less?

PostCSS 可以与 Sass、Less 和 Stylus 一起使用,也可以通过插件实现部分类似功能,但不能默认认为它是这些预处理器的完全替代品。

选择哪种方案取决于项目需求:

  • 只需要浏览器兼容性转换,可以使用 PostCSS 和 Autoprefixer;
  • 需要现代 CSS 降级,可以使用 postcss-preset-env
  • 需要 Sass 风格变量、Mixin 和函数,应评估 Sass 或对应 PostCSS 插件;
  • 已经使用 Sass 时,可以先由 Sass 生成 CSS,再交给 PostCSS 继续处理。

PostCSS 与 Vite、Next.js、Tailwind CSS

许多构建工具支持读取 PostCSS 配置,例如 Vite 和 Next.js。是否实际运行哪些插件,取决于项目依赖和配置,不能仅因为使用了这些工具就认为所有 PostCSS 插件都已启用。

Tailwind CSS 是 CSS 框架和工具链,不应直接称为“一个 PostCSS 插件”。某些版本或集成方式会通过 PostCSS 插件运行 Tailwind 的处理流程,但 Tailwind CSS 本身不等同于 PostCSS 插件。

PostCSS 的特点和优势

可组合和可定制

PostCSS 的处理能力由插件组合而成,项目只需要引入真正使用的插件:

源码 CSS → 导入 → 嵌套/变量转换 → 兼容性处理 → 压缩 → 输出 CSS

插件顺序会影响结果。例如:

  • postcss-import 通常应尽量放在前面;
  • Mixin、变量和嵌套插件通常应在 Autoprefixer 之前运行;
  • Cssnano 通常放在处理链末尾;
  • Stylelint 通常作为独立检查命令运行,而不是加入转换链。

构建速度

PostCSS 的构建速度取决于插件数量、文件规模、压缩设置、source map、缓存和构建工具。不能笼统地断言它一定比所有预处理器更快。选择 PostCSS 的主要理由应是插件生态、可组合性和与现有构建工具的集成能力。

不同 CSS 工具的构建时间对比示意图

自定义插件

如果现有插件不能满足需求,可以使用 PostCSS API 编写自定义插件,对 AST 进行检查或转换。PostCSS 生态中的插件数量会随着时间变化,不应引用固定的“356 个插件”作为当前数据。

可以在以下目录查找插件:

常用 PostCSS 插件

1. postcss-import

postcss-import 可以在构建阶段将一个 CSS 文件导入另一个 CSS 文件:

/* src/style.css */
@import './components/comp1.css';
@import './components/comp2.css';

.page {
  color: #222;
}

它与 Sass 中的 @import 看起来相似,但处理时机不同。postcss-import 通常在构建时内联文件,浏览器最终接收到的是合并后的 CSS。

这与浏览器原生 CSS @import 不同。原生 @import 会在浏览器运行时继续请求被导入的样式表,可能形成请求链;如果导入关系可以在构建阶段确定,通常可以使用 postcss-import 处理。

需要注意:

  • @import 通常应位于其他 CSS 规则之前;
  • 导入路径和扩展名要正确;
  • 循环导入会导致构建问题;
  • 动态决定的样式资源不一定适合在构建阶段内联。

参考:postcss-import

2. Autoprefixer:自动添加厂商前缀

Autoprefixer 根据 Browserslist 查询和兼容性数据,为目标浏览器补充必要的厂商前缀。它不会无条件添加 -webkit--moz--ms-,实际输出取决于目标浏览器和 Autoprefixer 版本。

输入:

label {
  user-select: none;
}

::selection {
  color: white;
  background: blue;
}

::placeholder {
  color: gray;
}

在面向现代浏览器的配置下,可能几乎不需要额外前缀;如果目标浏览器包含较旧版本,输出可能包含类似下面的内容:

label {
  -webkit-user-select: none;
  user-select: none;
}

::selection {
  color: white;
  background: blue;
}

旧版浏览器目标还可能生成 ::-moz-selection::-moz-placeholder:-ms-input-placeholder。这些前缀只是特定 Browserslist 配置下的示例,不应视为固定输出。

Autoprefixer 使用 Browserslist 来指定目标浏览器。例如在 package.json 中:

{
  "browserslist": [
    "defaults"
  ]
}

也可以在项目根目录创建 .browserslistrc

defaults

defaults 是一个会随 Browserslist 数据更新而变化的查询集合,不应把某一时期的浏览器版本列表当作永久固定值。项目也可以根据实际需求配置:

{
  "browserslist": [
    "last 2 versions",
    "not dead",
    "iOS >= 14"
  ]
}

参考:AutoprefixerBrowserslist

3. postcss-preset-env

postcss-preset-env 允许开发者使用部分现代 CSS,并根据目标浏览器进行转换。它可以处理现代 CSS 特性,例如部分嵌套、自定义媒体查询、逻辑属性和自定义选择器。

stage 用于控制启用的特性阶段,常见取值为 04,也可以设置为 false。具体可用特性和默认值应以当前插件版本文档为准。示例:

// postcss.config.cjs
module.exports = {
  plugins: [
    require('postcss-preset-env')({
      stage: 2
    })
  ]
}

现代浏览器已经支持原生 CSS Nesting,但如果项目需要兼容较旧浏览器,仍然可以让 preset-env 根据 Browserslist 进行转换。不要再笼统地说“现在的 CSS 不支持嵌套”。

输入:

article {
  background: purple;

  & .title {
    font-size: 6rem;
  }

  & li {
    list-style: none;
  }
}

在目标浏览器不支持嵌套时,可能转换为:

article {
  background: purple;
}

article .title {
  font-size: 6rem;
}

article li {
  list-style: none;
}

实际输出取决于插件版本、Browserslist 和具体特性配置。postcss-preset-env 通常也会集成 Autoprefixer,但仍应根据当前版本文档确认配置和输出。

参考:postcss-preset-env

4. postcss-nested

如果只想处理较接近 Sass 风格的嵌套,可以使用 postcss-nested

.card {
  color: #222;

  & .title {
    font-weight: 700;
  }
}

postcss-nestedpostcss-preset-env 的目标并不完全相同:前者更偏向 Sass 风格嵌套,后者更偏向根据目标浏览器转换标准或拟标准 CSS 特性。两者的输出不一定完全相同,不应重复启用相同功能而不进行测试。

参考:postcss-nested

5. postcss-mixins

Mixin 可以定义一组可复用的样式。经典 postcss-mixins 插件的语法示例:

@define-mixin reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

nav ul {
  @mixin reset-list;
}

转换结果:

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

需要注意不同 Mixin 插件包的语法可能不同。上面的 @define-mixin / @mixin 是经典 postcss-mixins 包的写法,不能与其他插件的 CSS Mixins 语法混用。

参考:postcss-mixins

6. Stylelint:CSS 代码检查

Stylelint 是 CSS、SCSS 等样式代码的检查工具,可以发现无效颜色、未知属性、选择器问题和团队规范问题。它通常独立运行,不应直接把 require('stylelint') 放入普通 PostCSS 转换插件数组。

例如创建 .stylelintrc.json

{
  "rules": {
    "color-no-invalid-hex": true
  }
}

下面的颜色会触发检查:

.invalid {
  color: #12xz;
}

执行检查:

pnpm exec stylelint "src/**/*.css"

也可以在 package.json 中添加脚本:

{
  "scripts": {
    "lint:css": "stylelint \"src/**/*.css\""
  }
}

默认情况下,Stylelint 不会启用所有规则。需要在配置文件中明确开启规则,或继承社区共享配置。

Stylelint 检查无效颜色的示意图

参考:Stylelint

7. Cssnano:CSS 压缩

Cssnano 用于减少生产环境 CSS 的体积,常见操作包括:

  • 删除不必要的空白和换行;
  • 删除部分冗余声明;
  • 压缩颜色值;
  • 优化规则和声明;
  • 删除可安全删除的注释。

输入:

* {
  padding: 0;
  margin: 0;
}

body {
  font-family: sans-serif, Calibri;
  font-size: 16px;
}

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

压缩后可能类似:

*{margin:0;padding:0}body{font-family:sans-serif,Calibri;font-size:16px}nav ul{list-style:none;margin:0;padding:0}

具体结果取决于 Cssnano 版本、preset 和配置。CSS 自定义属性不能在不了解引用关系的情况下任意重命名,不能把“重命名变量”作为普遍行为。

Cssnano 通常应放在处理链的后面:

require('cssnano')({
  preset: 'default'
})

参考:Cssnano

8. postcss-normalize

postcss-normalize 可以根据配置引入 normalize.csssanitize.css 的部分内容,帮助处理浏览器默认样式差异:

module.exports = {
  plugins: [
    require('postcss-normalize')
  ]
}

它的具体输出会受到 Browserslist 和插件配置影响。使用前应确认项目是否已经通过 CSS Reset、组件库或框架提供了同类功能,避免重复引入。

如何设置 PostCSS

安装依赖

推荐将依赖安装在项目本地,而不是全局安装:

pnpm add -D postcss postcss-cli postcss-import postcss-mixins postcss-preset-env cssnano
pnpm add -D stylelint

如果项目使用 npm,可以使用对应的 npm install -D 命令。全局安装 postcss-cligrunt-cli 容易造成不同项目之间的版本不一致,通常不推荐。

PostCSS 核心包本身不提供所有插件功能;使用哪些能力就需要安装对应插件。

使用 PostCSS CLI

PostCSS CLI 的常用形式是:

postcss <input.css> -o <output.css>
postcss <input.css> --dir <output-directory>
postcss <input.css> -o <output.css> --watch

例如:

pnpm exec postcss src/style.css -o public/style.css

如果不使用配置文件,也可以通过 --use 指定插件:

pnpm exec postcss src/style.css \
  --use postcss-import \
  --dir public \
  --watch

其中:

  • --use:指定要使用的插件;
  • --dir:指定输出目录;
  • -o--output:指定输出文件;
  • --watch-w:监听输入文件变化并重新构建。

直接在命令中写入多个插件会使命令变长,因此项目通常使用 postcss.config.cjspostcss.config.js

通过 package.json 脚本运行

{
  "scripts": {
    "postcss:build": "postcss src/style.css -o public/style.css",
    "postcss:watch": "postcss src/style.css -o public/style.css --watch"
  }
}

运行:

pnpm run postcss:build
pnpm run postcss:watch

如果使用 --dir public,例如:

postcss src/style.css --dir public

输入文件名为 style.css 时,通常会在 public 目录下生成同名文件。如果希望自定义输出文件名,应使用 -o

postcss src/style.css -o public/main.css

通过配置文件运行 PostCSS

在项目根目录创建 postcss.config.cjs

module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-mixins'),
    require('postcss-preset-env')({
      stage: 2
    }),
    require('cssnano')({
      preset: 'default'
    })
  ]
}

插件顺序通常应考虑以下原则:

  1. postcss-import 尽量放在前面,让后续插件能够处理被导入的内容;
  2. Mixin、变量、嵌套等语法转换应在兼容性处理和压缩之前;
  3. Autoprefixer 或 preset-env 应在压缩之前;
  4. Cssnano 通常放在最后;
  5. Stylelint 使用独立命令,不放入上述转换数组。

如果项目的 package.json 设置了:

{
  "type": "module"
}

可以使用 postcss.config.cjs 保持 CommonJS 配置;如果使用 postcss.config.js,则应根据构建工具的模块格式要求使用 export default

使用任务运行器或模块打包器

PostCSS 也可以与 Gulp、Grunt、Rollup、Webpack 等工具集成。现代项目通常由 Vite、Webpack 或其他构建工具加载 PostCSS 配置,只有维护旧项目时才更常见地直接使用 Grunt。

使用 Grunt

安装依赖:

pnpm add -D grunt grunt-cli @lodder/grunt-postcss
pnpm add -D postcss-import postcss-mixins postcss-preset-env cssnano

在项目根目录创建 Gruntfile.js

module.exports = function (grunt) {
  grunt.initConfig({
    postcss: {
      options: {
        processors: [
          require('postcss-import')(),
          require('postcss-mixins'),
          require('postcss-preset-env')({
            stage: 2
          }),
          require('cssnano')({
            preset: 'default'
          })
        ]
      },
      dist: {
        src: 'src/style.css',
        dest: 'public/style.css'
      }
    }
  })

  grunt.loadNpmTasks('@lodder/grunt-postcss')
}

这里需要注意:

  • 正确的方法名是 grunt.initConfig,不是 initCnfig
  • processors 中应放 PostCSS 转换插件;
  • Stylelint 应单独执行,不应作为这里的普通处理器;
  • cssnano 通常放在处理链最后;
  • 不同版本的 Grunt 插件对处理器配置可能略有差异,应以实际插件文档为准。

运行任务:

pnpm exec grunt postcss

什么时候使用 PostCSS?

适合使用 PostCSS 的场景包括:

  • 需要根据 Browserslist 自动添加浏览器前缀;
  • 需要将部分现代 CSS 转换为旧浏览器可以理解的语法;
  • 需要构建阶段内联 CSS 文件;
  • 需要把 CSS 检查、转换和压缩接入构建流程;
  • 需要编写自定义 CSS 转换插件;
  • 已经使用 Vite、Webpack、Rollup 等支持 PostCSS 的构建工具。

不应为了“使用 PostCSS”而堆叠大量插件。插件越多,构建时间、调试难度和输出差异也可能增加。应根据目标浏览器、项目语法和部署需求选择最小可用配置。

总结

  1. PostCSS 核心负责 CSS AST 的解析、插件调度和输出;
  2. PostCSS 的具体功能来自插件,不是一个自带全部特性的预处理器;
  3. postcss-import 通常在构建阶段内联 CSS,和浏览器原生 @import 不同;
  4. Autoprefixer 的输出取决于 Browserslist 和目标浏览器,不会固定添加所有厂商前缀;
  5. 现代浏览器已经支持 CSS Nesting,但旧浏览器兼容仍可能需要 preset-env 或嵌套插件;
  6. postcss-preset-envpostcss-nestedpostcss-mixins 的语法和目标并不完全相同;
  7. Stylelint 通常作为独立的 CSS 检查工具运行,不应直接放进普通 PostCSS 插件数组;
  8. Cssnano 一般放在处理链最后,并且压缩结果取决于版本和 preset;
  9. 推荐使用项目本地依赖、配置文件和 package scripts,不建议依赖全局 CLI;
  10. PostCSS 是否适合项目,应根据浏览器目标、代码规模、插件需求和构建工具综合判断。

参考资料

原文资料:2022 首次更文挑战

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS