最近很火的TailwindCSS
有一个功能:
可以将项目未使用的css
选择器从编译后css
文件中移除。
这个功能是PurgeCSS
实现的。
链接TailwindCSS
与PurgeCSS
的,则是一个postCSS
插件@fullhuman/postcss-purgecss
。
不仅TailwindCSS
,还有很多知名项目中使用了postCSS
插件。比如:
很多人在项目中使用autoprefixer
插件,为css
选择器增加不同的浏览器前缀。
在其内部会根据browserslist指定浏览器版本。
再去caniuse查找该浏览器版本兼容性支持情况。
最后通过postCSS
的能力改写不支持的css
属性。
可以看到,postCSS
正越来越成为前端项目必不可少的依赖。
同时也有很多关于postCSS
的误区,比如认为他是和Less
、Sass
一样的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中选择:
-
语言: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:单独的注释。
selectors
、at-rule
的参数以及value
的注释在节点的node
属性内
实现一个简单的插件
接下来我们从一个插件的实现来了解开发者如何介入postCSS
编译流程。
postcss-focus会为所有:hover
选择器增加:focus
以提高键盘操作的可用性。
对于如下代码:
.a:hover, .b:hover, .c:hover {
opacity: .5;
}
经过该插件处理后会输出:
.a:hover, .b:hover, .c:hover, .a:focus, .b:focus, .c:focus {
opacity: .5;
}
你可以安装postcss
、postcss-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源码的实现逻辑:
-
postCSS
将输入的css
解析为AST
-
遍历
AST
中所有Rule
类型节点 -
维护一个数组,遍历这个节点的所有
selector
,每遍历到一个包含:hover
的selector
就往数组中push
一个:focus
的selector
-
将2中得到的数组
concat
到该节点已有的selectors
后 -
根据改变后的
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
提供了详细的插件创建文档。甚至提供了create-postcss-plugin用来创建插件的模版代码。
更多可能性
由于提供了表达、改写css AST
的能力,postCSS
的插件可以实现非常多功能。比如:
postcss-functions
上文介绍了Declaration
节点表达css属性的键值对,其中值为字符串类型。
那么完全可以自定义值的解析规则。
body {
color: getColor();
}
通过定义getColor
函数,并在AST
中将其解析为函数执行,就能在css
文件中用js
写逻辑代码。
这就是postcss-functions
stylelint
配置不同的lint
规则,实现css
的静态语法检测。这就是stylelint
总结
当前postCSS
插件按功能划分大体有如下几类:
-
解决全局
css
问题,比如提供css module支持 -
使用未全面兼容的
css
特性,比如autoprefixer -
格式化,提高
css
可读性 -
图片和文字处理
-
linters,比如
stylelint
-
不同语法的
css
支持,比如postcss-html可以解析类html
文件中<style>
标签内的css
语法
读到这里,相信你会同意:相比Less
、Sass
,postCSS
才是css
处理领域的大杀器。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!