Skip to content

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

最近很火的TailwindCSS有一个功能:

可以将项目未使用的css选择器从编译后css文件中移除。

这个功能是PurgeCSS实现的。

链接TailwindCSSPurgeCSS的,则是一个postCSS插件@fullhuman/postcss-purgecss

不仅TailwindCSS,还有很多知名项目中使用了postCSS插件。比如:

很多人在项目中使用autoprefixer插件,为css选择器增加不同的**「浏览器前缀」**。

在其内部会根据 browserslist[1] 指定浏览器版本。

再去 caniuse[2] 查找该浏览器版本兼容性支持情况。

最后通过postCSS的能力改写不支持的css属性。

可以看到,postCSS正越来越成为前端项目必不可少的依赖。

同时也有很多关于postCSS的误区,比如认为他是和LessSass一样的**「css 预处理器」**。

本文会自底向上介绍postCSS,希望通过此文让你对这款大杀器有更深的认识。

什么是 postCSS

postCSS是一款css编译器。

类比Babel家族的@babel/parser可以将js代码解析为AST(抽象语法树),再利用众多插件(@babel/plugin-xx)的能力改写AST,最终输出改写后的js代码。

postCSS利用自身的parser可以将css代码解析为AST,再利用众多插件(上文介绍的autoprefixer就是一种)改写AST,最终输出改写后的css代码。

从这点就能看出其与Less这样的**「css 预处理器」**的不同 —— postCSS的输入与输出产物都是css文件。

因此,postCSS也被成为**「后处理器」**,因为其通常在css处理链条的最后端。

postCSS 的 AST

你可以在 astexplorer[3] 中选择:

  • 语言:css

  • parser:postCSS

来了解postCSS如何解析css

比如,对于如下css代码:

/** * I am KaSong */@media screen and (min-width: 900px) {  article {    padding: 1rem 3rem;  }}ul { margin: 3rem;}ul li { padding: 5px;}

会被postCSS解析为如下树结构的AST

节点有如下几种类型:

  • Root:根节点,代表一个css文件

  • AtRule:以@开头的申明,比如@charset "UTF-8"@media (screen) {}

  • Rule:内部包含定义的选择器,比如input, button {}

  • Declaration:key-value键值对,比如color: black;

  • Comment:单独的注释。selectorsat-rule的参数以及value的注释在节点的node属性内

实现一个简单的插件

接下来我们从一个插件的实现来了解开发者如何介入postCSS编译流程。

postcss-focus[4] 会为所有:hover选择器增加:focus以提高键盘操作的可用性。

对于如下代码:

.a:hover, .b:hover, .c:hover {  opacity: .5;}

经过该插件处理后会输出:

.a:hover, .b:hover, .c:hover, .a:focus, .b:focus, .c:focus {  opacity: .5;}

你可以安装postcsspostcss-focus后通过如下demo在控制台看到结果:

const postcssFocus = require('postcss-focus');const postcss = require('postcss');const fs = require('fs');// 输入的css文件地址const from = 'src/a.css';const to = 'output/a.css';fs.readFile(from, (err, css) => {  postcss(postcssFocus).process(css, { from, to }).then(result => {    console.log(result.css)  })  })

接下来我们分析 postcss-focus 源码 [5] 的实现逻辑:

  1. postCSS将输入的css解析为AST

  2. 遍历AST中所有Rule类型节点

  3. 维护一个数组,遍历这个节点的所有selector,每遍历到一个包含:hoverselector就往数组中push一个:focusselector

  4. 将 2 中得到的数组concat到该节点已有的selectors

  5. 根据改变后的AST输出新的css

核心源码如下:

{  postcssPlugin: 'postcss-focus',  // 步骤1  Rule: rule => {    // 步骤2    if (rule.selector.includes(':hover')) {      let focuses = []      for (let selector of rule.selectors) {        if (selector.includes(':hover')) {          let replaced = selector.replace(/:hover/g, ':focus')          if (!hasAlready(rule.parent, replaced)) {            focuses.push(replaced)          }        }      }      // 步骤3      if (focuses.length) {        rule.selectors = rule.selectors.concat(focuses)      }    }  }}

这个插件只是为了演示插件的基本工作方法,实际上该插件实现的比较粗糙。

postCSS提供了详细的插件创建文档 [6]。甚至提供了 create-postcss-plugin[7] 用来创建插件的模版代码。

更多可能性

由于提供了表达、改写css AST的能力,postCSS的插件可以实现非常多功能。比如:

postcss-functions

上文介绍了Declaration节点表达**「css 属性」的键值对,其中值为「字符串」**类型。

那么完全可以自定义值的解析规则。

body {  color: getColor();}

通过定义getColor函数,并在AST中将其解析为函数执行,就能在css文件中用js写逻辑代码。

这就是 postcss-functions[8]

stylelint

配置不同的lint规则,实现css的静态语法检测。这就是 stylelint[9]

总结

当前postCSS插件按功能划分大体有如下几类:

  • 解决全局css问题,比如提供 css module[10] 支持

  • 使用未全面兼容的css特性,比如 autoprefixer[11]

  • 格式化,提高css可读性

  • 图片和文字处理

  • linters,比如stylelint

  • 不同语法的css支持,比如 postcss-html[12] 可以解析类html文件中<style>标签内的css语法

读到这里,相信你会同意:相比LessSasspostCSS才是css处理领域的大杀器。

参考资料

[1]

browserslist: https://github.com/browserslist/browserslist

[2]

caniuse: https://caniuse.com/#search=

[3]

astexplorer: https://astexplorer.net/

[4]

postcss-focus: https://www.npmjs.com/package/postcss-focus

[5]

postcss-focus 源码: https://github.com/postcss/postcss-focus/blob/master/index.js

[6]

插件创建文档: https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md

[7]

create-postcss-plugin: https://github.com/csstools/create-postcss-plugin

[8]

postcss-functions: https://www.npmjs.com/package/postcss-functions

[9]

stylelint: https://github.com/stylelint/stylelint

[10]

css module: https://github.com/madyankin/postcss-modules

[11]

autoprefixer: https://github.com/postcss/autoprefixer

[12]

postcss-html: https://github.com/gucong3000/postcss-html

前端 社群








下方加 Nealyang 好友回复「 加群」即可。







如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:


1. 点个「在看」,让更多人也能看到这篇文章



点赞和在看就是最大的支持