PostCSS
第一章:初识
一、简介
1. CSS 后处理器
自己写的 CSS 代码,想让 CSS 兼容各种浏览器、压缩、编写 CSS 时对代码规范检查等。所以就有了 CSS 后处理器。
CSS 后处理器是在原生的 CSS 代码的基础上面做处理,常见的处理工作如下:
- 兼容性处理:自动添加浏览器前缀(如 -webkit-、-moz- 和 -ms-)以确保跨浏览器兼容性。这种后处理器的一个典型例子是 autoprefixer。
- 代码优化与压缩:移除多余的空格、注释和未使用的规则,以减小 CSS 文件的大小。例如,cssnano 是一个流行的 CSS 压缩工具。
- 功能增强:添加新的 CSS 特性,使开发者能够使用尚未在所有浏览器中实现的 CSS 功能。例如,PostCSS 是一个强大的 CSS 后处理器,提供了很多插件来扩展 CSS 的功能。
- 代码检查与规范:检查 CSS 代码的质量,以确保代码符合特定的编码规范和最佳实践。例如,stylelint 是一个强大的 CSS 检查工具,可以帮助你发现和修复潜在的问题。
PostCSS 本身只是实现了对 CSS 代码的 AST 功能,具体代码转换处理还需要借助插件或预设。
2. 是什么
PostCSS 是一个基于 JavaScript 转换 CSS 的工具。用于对 CSS 代码进行转换和处理。它通过插件系统提供了强大的功能,例如自动添加浏览器前缀、优化代码、支持现代 CSS 特性等。PostCSS 不仅可以作为独立工具使用,还可以与其他预处理器(如 Sass 或 Less)结合使用。
总结:CSS 语法转换的工具。

这一点有点像 webpack,webpack 本身仅做依赖分析、抽象语法树分析,其他的操作是靠插件和加载器完成的。
文档
官方文档:PostCSS
中文文档:PostCSS 中文网
3. 安装
PostCSS 是基于 node 编写的,因此可以使用 npm 安装。
npm i -D postcssPostCSS 库提供了对应的 js api 用于转换代码,如果你想使用 PostCSS 的一些高级功能,或者想开发 PostCSS 插件,就要 API 使用 PostCSS,API 的文档地址是:http://api.postcss.org
不过绝大部分时候,我们都是使用者,并不希望使用代码的方式来使用 PostCSS。
因此,我们可以再安装一个 postcss-cli,通过命令行来完成编译。
npm i -D postcss-clipostcss-cli 提供一个命令,它调用 PostCSS 中的 API 来完成编译。
postcss 源码文件 -o 输出文件更多命令查看 postcss-cli
第二章:配置文件
一、位置
postcss 有自己的配置文件,该配置文件会影响 postcss 的某些编译行为。
配置文件的默认名称:postcss.config.js
当使用 postcss-cli 或者构建工具(webpack、vite)来进行集成的时候,postcss 会自动加载配置文件。
module.exports = {
map: false, // 关闭source-map
plugins: [
require("autoprefixer")({
overrideBrowserslist: "last 10 versions",
}),
],
}postcss 配置文件最主要的其实就是做插件的配置。postcss 官网没有提供配置文件相关的文档,但是我们可以在:postcss/postcss-load-config 这个地方看到 postcss 配置文件所支持的配置项目。
二、配置项目
plugins:一个数组,里面包含要使用到的 postcss 的插件以及相关的插件配置。
module.exports = {
plugins: [
require("autoprefixer"),
require("cssnano")({ preset: "default" }),
],
};map:是否生成源码映射,对应的值为一个对象
module.exports = {
map: { inline: false },
plugins: [/* Your plugins here */],
};默认值为 false,因为源码映射一般是会单独存放在一个文件里面。
syntax:用于指定 postcss 应该使用的 CSS 语法,默认情况下 postcss 处理的是标准的 CSS,但是有可能你的 CSS 是使用预处理器来写的,这个时候 postcss 是不认识的,所以这个时候需要安装对应的插件并且在配置中指明 syntax
module.exports = {
syntax: "postcss-scss",
plugins: [/* Your plugins here */],
};安装 postcss-scss 这个插件,并且在配置文件中指定 syntax 为 postcss-scss,之后 PostCSS 就能够认识你的 sass 语法。
parser:配置自定义解析器。Postcss 默认的解析器为 postcss-safe-parser,负责将 CSS 字符串解析为 CSS AST,如果你要用其他的解析器,那么可以配置一下。
const customParser = require("my-custom-parser");
module.exports = {
parser: customParser,
plugins: [/* Your plugins here */],
};stringifier:自定义字符串化器。用于将 CSS AST 转回 CSS 字符串。如果你要使用其他的字符串化器,那么也是可以在配置文件中国呢进行指定的。
const customStringifier = require("my-custom-stringifier");
module.exports = {
stringifier: customStringifier,
plugins: [/* Your plugins here */],
};最后还剩下两个配置项:from、to,这两个选项官方是不建议你配置的,而且你配置的大概率还会报错,报错信息如下:
Config Error: Can not set from or to options in config file, use CLI arguments instead
这个提示的意思是让我们不要在配置文件里面进行配置,而是通过命令行参数的形式来指定。
至于为什么,官方其实解释得很清楚了:
In most cases options.from && options.to are set by the third-party which integrates this package (CLI, gulp, webpack). It's unlikely one needs to set/use options.from && options.to within a config file.
因为在实际开发中,我们更多的是会使用构建工具(webpack、vite),这些工具会去指定入口文件和出口文件。
第三章:常见插件
光使用 postcss 是没有多少意义的,要让它真正的发挥作用,需要插件。
插件市场:PostCSS Plugins
一、postcss-preset-env
为什么要有?
过去使用 postcss 的时候,往往会使用大量的插件,它们各自解决一些问题。
这样导致的结果是安装插件、配置插件都特别的繁琐。
于是出现了这么一个插件 postcss-preset-env,它称之为 postcss 预设环境,大意就是它整合了很多的常用插件到一起,并帮你完成了基本的配置,你只需要安装它一个插件,就相当于安装了很多插件了。
作用
postcss-preset-env 主要就是让开发者可以使用最新的的 CSS 语法,同时为了兼容会自动的将这些最新的 CSS 语法转换为旧版本浏览器能够支持的代码。
postcss-preset-env 的主要作用是:
- 让你能够使用最新的 CSS 语法,如:CSS Grid(网格布局)、CSS Variables(变量)等。
- 自动为你的 CSS 代码添加浏览器厂商前缀,如:-webkit-、-moz- 等。
- 根据你的浏览器兼容性需求,将 CSS 代码转换为旧版浏览器兼容的语法。
- 优化 CSS 代码,如:合并规则、删除重复的代码等。
快速使用
1)安装。
pnpm add postcss-preset-env -D2)在 postcss 配置中加入下面的配置。
module.exports = {
plugins: {
"postcss-preset-env": {} // {} 中可以填写插件的配置
}
}该插件的功能很多,下面一一介绍。
1. 自动的厂商前缀
某些新的 css 样式需要在旧版本浏览器中使用厂商前缀方可实现。
例如:
::placeholder {
color: red;
}该功能在不同的旧版本浏览器中需要书写为。
::-webkit-input-placeholder {
color: red;
}
::-moz-placeholder {
color: red;
}
:-ms-input-placeholder {
color: red;
}
::-ms-input-placeholder {
color: red;
}
::placeholder {
color: red;
}要完成这件事情,需要使用 autoprefixer 库。
而 postcss-preset-env 内部包含了该库,自动有了该功能。
如果需要调整兼容的浏览器范围,可以通过下面的方式进行配置。
方式 1:在 postcss-preset-env 的配置中加入 browsers
module.exports = {
plugins: {
"postcss-preset-env": {
browsers: [
"last 2 version",
"> 1%"
]
}
}
}方式 2【推荐】:添加 .browserslistrc 文件
创建文件 .browserslistrc,填写配置内容。
last 2 version
> 1%方式 3【推荐】:在 package.json 的配置中加入 browserslist
"browserslist": [
"last 2 version",
"> 1%"
]browserslist 是一个多行的(数组形式的)标准字符串。
它的书写规范多而繁琐,详情见:https://github.com/browserslist/browserslist
一般情况下,大部分网站都使用下面的格式进行书写。
last 2 version
> 1% in CN
not ie <= 8last 2 version:浏览器的兼容最近期的两个版本。> 1% in CN:匹配中国大于 1% 的人使用的浏览器,in CN可省略。not ie <= 8:排除掉版本号小于等于 8 的 IE 浏览器。
默认情况下,匹配的结果求的是并集。
你可以通过网站:https://browserl.ist/ 对配置结果覆盖的浏览器进行查询,查询时,多行之间使用英文逗号分割。
browserlist 的数据来自于 CanIUse 网站,由于数据并非实时的,所以不会特别准确。
2. 未来的 CSS 语法
CSS 的某些前沿语法正在制定过程中,没有形成真正的标准,如果希望使用这部分语法,为了浏览器兼容性,需要进行编译。
过去,完成该语法编译的是 cssnext 库,不过有了 postcss-preset-env 后,它自动包含了该功能。
你可以通过 postcss-preset-env 的 stage 配置,告知 postcss-preset-env 需要对哪个阶段的 css 语法进行兼容处理,它的默认值为 2。
module.exports = {
map: false, // 关闭source-map
plugins: {
"postcss-preset-env": {
stage: 0 // 哪怕是处于草案阶段的语法,也需要转换
}
}
}一共有 5 个阶段可配置:
- Stage 0: Aspirational - 只是一个早期草案,极其不稳定。
- Stage 1: Experimental - 仍然极其不稳定,但是提议已被 W3C 公认。
- Stage 2: Allowable - 虽然还是不稳定,但已经可以使用了。
- Stage 3: Embraced - 比较稳定,可能将来会发生一些小的变化,它即将成为最终的标准。
- Stage 4: Standardized - 所有主流浏览器都应该支持的 W3C 标准。
了解了以上知识后,接下来了解一下未来的 css 语法,尽管某些语法仍处于非常早期的阶段,但是有该插件存在,编译后仍然可以被浏览器识别。
1)变量
未来的 css 语法是天然支持变量的。
在 :root{} 中定义常用变量,使用 -- 前缀命名变量。
:root {
--lightColor: #ddd;
--darkColor: #333;
}
a {
color: var(--lightColor);
background: var(--darkColor);
}编译后,仍然可以看到原语法,因为某些新语法的存在并不会影响浏览器的渲染,尽管浏览器可能不认识。
如果不希望在结果中看到新语法,可以配置postcss-preset-env的 preserve 为 false。
2)自定义选择器
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
@custom-selector :--enter :focus,:hover;
a:--enter{
color: #f40;
}
:--heading{
font-weight:bold;
}
:--heading.active{
font-weight:bold;
}编译后
a:focus,a:hover{
color: #f40;
}
h1,h2,h3,h4,h5,h6{
font-weight:bold;
}
h1.active,h2.active,h3.active,h4.active,h5.active,h6.active{
font-weight:bold;
}3)嵌套
与 LESS 相同,只不过嵌套的选择器前必须使用符号 &。
.a {
color: red;
& .b {
color: green;
}
& > .b {
color: blue;
}
&:hover {
color: #000;
}
}编译后
.a {
color: red
}
.a .b {
color: green;
}
.a>.b {
color: blue;
}
.a:hover {
color: #000;
}二、postcss-apply
该插件可以支持在 css 中书写属性集。
类似于 LESS 中的混入,可以利用 CSS 的新语法定义一个 CSS 代码片段,然后在需要的时候应用它。
:root {
--center: {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
};
}
.item {
@apply --center;
}编译后
.item {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}实际上,该功能也属于 cssnext,不知为何
postcss-preset-env没有支持。
三、postcss-color-function
该插件支持在源码中使用一些颜色函数。
body {
/* 使用颜色#aabbcc,不做任何处理,等同于直接书写 #aabbcc */
color: color(#aabbcc);
/* 将颜色#aabbcc透明度设置为90% */
color: color(#aabbcc a(90%));
/* 将颜色#aabbcc的红色部分设置为90% */
color: color(#aabbcc red(90%));
/* 将颜色#aabbcc调亮50%(更加趋近于白色),类似于less中的lighten函数 */
color: color(#aabbcc tint(50%));
/* 将颜色#aabbcc调暗50%(更加趋近于黑色),类似于less中的darken函数 */
color: color(#aabbcc shade(50%));
}编译后
body {
/* 使用颜色#aabbcc,不做任何处理,等同于直接书写 #aabbcc */
color: rgb(170, 187, 204);
/* 将颜色#aabbcc透明度设置为90% */
color: rgba(170, 187, 204, 0.9);
/* 将颜色#aabbcc的红色部分设置为90% */
color: rgb(230, 187, 204);
/* 将颜色#aabbcc调亮50%(更加趋近于白色),类似于less中的lighten函数 */
color: rgb(213, 221, 230);
/* 将颜色#aabbcc调暗50%(更加趋近于黑色),类似于less中的darken函数 */
color: rgb(85, 94, 102);
}四、purgecss
该插件专门用于移除没有使用到的 CSS 样式的工具,相当于是 CSS 版本的 tree shaking(树摇),它会找到你文件中实际使用的 CSS 类名,并且移除没有使用到的样式,这样可以有效的减少 CSS 文件的大小,提升传输速度。
官网地址:PurgeCSS
安装该插件:
pnpm add @fullhuman/postcss-purgecss -D接下来我们在 src 下面创建一个 index.html,书写如下的代码:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="container">
<div class="box1"></div>
</div>
</body>该 html 只用到了少量的 CSS 样式类。
目前我们的 index.css 代码如下:
@import "a.css";
@import "b.css";
.a {
color: red;
&.b {
color: green;
transform: translate(100px);
}
&>.b {
color: blue;
}
&:hover {
color: #000;
}
}
.container {
font-size: 20px;
}
p {
color: red;
}接下来我在 postcss.config.js 配置文件中引入 @fullhuman/postcss-purgecss 这个插件,具体的配置如下:
module.exports = {
plugins: [
require("postcss-import")({
path: ["src/css"]
}),
require("postcss-preset-env")({
stage: 2,
}),
require("@fullhuman/postcss-purgecss")({
content: ['./src/**/*.html']
})
],
};我们引入 @fullhuman/postcss-purgecss 插件后,还做了 content 这个配置项目的相关配置,该配置项表示我具体的参照文件。也就是说,CSS 样式类有没有用上需要有一个具体的参照文件。
最终编译出来的结果如下:
.box1 {
background-color: red;
}
.container {
font-size: 20px;
}@fullhuman/postcss-purgecss 这个插件除了 content 这个配置项,还有一个配置项也非常的常用:
- safelist:可以指定一个字符串的值,或者指定一个正则表达式,该配置项目所对应的值(CSS 样式规则)始终保留,即便在参照文件中没有使用到也需要保留
const purgecss = require('@fullhuman/postcss-purgecss');
module.exports = {
plugins: [
// 其他插件...
purgecss({
content: ['./src/**/*.html', './src/**/*.js'],
safelist: [/^active-/],
}),
],
};safelist 所对应的值的含义为:匹配 active- 开头的类名,这些类名即便在项目文件中没有使用到,但是也不要删除。
[扩展] postcss-import
该插件可以让你在 postcss 文件中导入其他样式代码,通过该插件可以将它们合并。
1)安装
pnpm add postcss-import -D2)配置
module.exports = {
plugins: [
require("postcss-import"),
],
};
module.exports = {
plugins: [
require("postcss-import")({
path: ["src/css"],
plugins: [
postcssNested(),
],
}),
// 其他插件...
],
};一些配置项:
- path:设置查找 CSS 文件的路径,默认为当前文件夹。
- plugins:允许你指定在处理被 @import 引入的 CSS 文件时使用的其他 PostCSS 插件。这些插件将在 postcss-import 合并文件之前对被引入的文件进行处理,之后再进行文件的合并。
更多配置项 postcss/postcss-import
由于后续会将 postcss 加入到 webpack 中,而 webpack 本身具有依赖分析的功能,所以该插件的实际意义不大。
[扩展] stylelint
这个不依赖 postcss,只是它写了一个插件来兼容 postcss。
在实际的开发中,我们可能会错误的或不规范的书写一些 css 代码,stylelint 会即时的发现错误。
由于不同的公司可能使用不同的 CSS 书写规范,stylelint 为了保持灵活,它本身并没有提供具体的规则验证。
你需要安装或自行编写规则验证方案。通常,我们会安装 stylelint-config-standard 库来提供标准的 CSS 规则判定。
pnpm add stylelint stylelint-config-standard -D这里安装了两个依赖:
- stylelint:做 CSS 代码风格校验,但是具体的校验规则它是不知道了,需要我们提供具体的校验规则。
- stylelint-config-standard:这是 stylelint 的一套校验规则,并且是一套标准规则。
安装好后,我们需要告诉 stylelint 使用该库来进行规则验证。
告知的方式有多种,比较常见的是使用文件 .stylelintrc。
// .styleintrc
{
"extends": "stylelint-config-standard"
}怎么结合到 postcss 中?
module.exports = {
map: false, // 关闭source-map
plugins: {
"postcss-preset-env": {
stage: 0, //哪怕是处于草案阶段的语法,也需要转换
preserve: false
},
"postcss-apply": {},
"postcss-color-function": {},
"stylelint": {}
}
}此时,如果你的代码出现不规范的地方,编译时将会报出错误。
body {
background: #f4;
}
发生了两处错误:
- 缩进应该只有两个空格。
- 十六进制的颜色值不正确。
如果某些规则并非你所期望的,可以在配置中进行设置。
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": null
}
}设置为 null 可以禁用该规则,或者设置为 4,表示一个缩进有 4 个空格。具体的设置需要参见 stylelint 文档:Rules
检查出来的问题能否自动修复?只需要将 stylelint 插件的 fix 配置项配置为 true 即可。
// postcss 配置主要其实就是做插件的配置
module.exports = {
plugins: [
require("stylelint")({
fix: true
}),
],
};但是这种错误报告需要在编译时才会发生,如果我希望在编写代码时就自动在编辑器里报错呢?
既然想在编辑器里达到该功能,那么就要在编辑器里做文章。
安装 vscode 的插件 stylelint 即可,它会读取你工程中的配置文件,按照配置进行实时报错。
实际上,如果你拥有了 stylelint 插件,可以不需要在 postcss 中使用该插件了。
第四章:自定义插件
一、编写插件步骤
在 PostCSS 官网,实际上已经介绍了如何去编写一个自定义插件:https://postcss.org/docs/writing-a-postcss-plugin
1)需要有一个模板
module.exports = (opts = {}) => {
return {
postcssPlugin: '插件名字',
Once (root) {
// 整个文件开始时只触发一次,因为文件只有一个 Root 根节点
},
Declaration (decl) {
// 每当遍历到任何一个“属性声明”时都会触发,decl 就是当前遍历到的那个声明对象
}
}
}
// 必须有这句话来标识这是一个 PostCSS 插件
module.exports.postcss = true;2)接下来就可以在插件里面添加一组监听器,对应的能够设置的监听器如下:
- Root(根):AST 树的最高层节点,代表整个 CSS 文件。
- AtRule(@规则):所有以
@开头的语句,比如@charset "UTF-8"或@media (screen) {}。 - Rule(规则):包含选择器和内部声明的代码块,比如
input, button {}。 - Declaration(声明):键值对,比如
color: black;。 - Comment(注释):独立存在的注释。注意,写在选择器或值中间的内联注释是被存在父节点的
raws属性里的,而不是单独的节点。
二、具体示例
现在在我们的 src 中新建一个 my-plugin.js 的文件,代码如下:
module.exports = (opts = {}) => {
// Plugin creator to check options or prepare caches
return {
postcssPlugin: "PLUGIN NAME",
Declaration(decl) {
console.log(decl.prop, decl.value)
}
};
};
module.exports.postcss = true;在上面的代码中,我们添加了 Declaration 的监听器,通过该监听器能够拿到 CSS 文件中所有的声明。
接下来我们就可以对其进行相应的操作。
现在我们来做一个具体的示例:编写一个插件,该插件能够将 CSS 代码中所有的颜色统一转为十六进制。
这里我们需要使用到一个依赖包:color 该依赖就是专门做颜色处理的
pnpm add color -D之后通过该依赖所提供的 hex 方法来进行颜色值的修改,具体代码如下:
const Color = require("color");
module.exports = (opts = {}) => {
// Plugin creator to check options or prepare caches
return {
postcssPlugin: "convertColorsToHex",
Declaration(decl) {
// 先创建一个正则表达式,提取出如下的声明
// 因为如下的声明对应的值一般都是颜色值
const colorRegex = /(^color)|(^background(-color)?)/;
if (colorRegex.test(decl.prop)) {
try {
// 将颜色值转为 Color 对象,因为这个 Color 对象对应了一系列的方法
// 方便我们进行转换
const color = Color(decl.value);
// 将颜色值转换为十六进制
const hex = color.hex();
// 更新属性值
decl.value = hex;
} catch (err) {
console.error(
`[convertColorsToHex] Error processing ${decl.prop}: ${error.message}`
);
}
}
},
};
};
module.exports.postcss = true;第五章:与构建工具结合
一、webpack 集成
官方文档:postcss-loader
我们的 css 代码,需要先交给 postcss 处理变成普通的 css,然后用 css-loader 变成 js,之后使用 style-loader 把 css 添加到 style 元素中。
1)安装依赖
npm install --save-dev postcss-loader postcss2)配置 webpack
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
mode: "development",
devtool: "source-map",
module: {
rules: [
{
test: /\.css$/, use: ["style-loader", "css-loader?modules", "postcss-loader"]
}
]
},
devServer: {
open: true
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
}3)创建 postcss.config.js