PostCss
是一个CSS
后处理工具
PostCss
是什么
首先,聊PostCss
之前,我们得知道什么是CSS
后处理工具。我们比较熟悉的Less,Sass,Stylus
,这类工具都属于CSS
预处理工具通过特殊的规则、文本格式最终生成CSS
文件。而PostCss
则是对CSS
进行处理,最终生成CSS
。
多数人最早接触和使用的应该是Autoprefixer
这款插件,Autoprefixer
的功能是:以 Can I Use 上的 浏览器支持数据 为基础,自动处理兼容性问题。
# Autoprefixer 处理前的CSS样式
.container {
display: flex;
}
.item {
flex: 1;
}
# Autoprefixer 处理后的CSS样式
.container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.item {
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
通过使用Autoprefixer
插件,很大程度上节省了CSS
重复样式的编写。Autoprefixer
正是PostCss
众多插件中的一款,查找更多插件,点这里。
PostCss
处理Css
过程
作为一款可安装使用各类插件的工具,PostCss
提供的API
还是很简洁明了的(吐槽一下Less,什么鬼玩意儿,API文档都不写的)
- 将
Css
文件信息处理成树型结构的Js
对象。 - 根据配置插件的顺序对树型结构的
Js
对象 进行操作。 - 最终将处理后获得的树型结构的
Js
对象输出为Css
文件。
那么关键点就在与Css
被处理后生成的树型结构的Js
对象,那么先让我们看一看它的小裙裙里藏着什么。
PostCss
处理Css
详解
- 下图为一个很标准的
Css
,有注释、带有@
的媒体查询、以及选择器样式。
- 上面的
Css
最终会处理为下图结构,通过打印信息我们可以发现树型结构的Js
对象是一个名为Root
的构造函数,而起树型结构的nodes
节点下还有Commont
,AtRule
,Rule
构造函数。
- 上面的
- 树型结构的
Js
对象在最后会处理成名为Result
的构造函数,如下图,带有css
这个属性,包含完整的Css
信息,最终会被写入到文件中。
PostCss
中的各种构造函数
在上面部分关于 PostCss
处理Css
中,生成了很多构造函数。而 PostCss
的神奇功能也都围绕着这些构造函数,接下来我们一一介绍。
Root
:PostCss
处理过的Css
,整个处理过程基本上都在围绕着Root
,Commont
,AtRule
,Rule
都是它的子节点。-
Commont
:Css
中的注释信息,注释的内容在Commont.text
下。
-
AtRule
: 为带@
标识的部分,name
为标识名称,params
为标识参数。nodes
为内部包含的其他子节点,可以是Commont
,AtRule
,Rule
,这让我们可以自定义更多的规则,
-
Rule
: 选择器样式部分,一个选择器代表一个Rule
,选择器对应的样式列表nodes
为Declaration
构造函数,
-
Declaration
: 为Css
样式属性,prop
为样式属性,value
为样式值。可给Rule
手动添加样式属性,也可以修改prop
,value
。上文提到的Autoprefixer
就是通过clone
当前属性,修改prop
并添加到选择器下。
Result
: 通过root.toResult()
方法可以获取到带有css
全文本信息的Result
对象,也代表这我们PostCss
单个插件到了尾声。接下来直接将result.css
写入对应的文件即可。
如何使用 PostCss
插件
PostCss
插件有很多种使用方式,
- 可以配合在
postcss-loader
的options
配置各种插件
plugins: [
themePlugin({}),
autoprefixer({})
]
- 也可以直接在
Node
程序中使用
postcss([themePlugin({})])
.process(css, {from: ``, to: ``})
.then(result => {
// 根据配置文件themeList,分别处理对应的文件,打包各css 文件
})
.catch(error => {
throw new Error(error)
})
如何编写一个 PostCss
插件
上文中,我们对Css
处理后生成的Root
以及其节点下的Commont
,AtRule
,Rule
, Declaration
有了基本的认识,那么我们是如何获得Root
,又将拿这些构造函数做些什么呢。
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-test-plugin', function (opts) {
opts = opts || {}; // 处理 options
return function (root, result) {
//遍历所有的选择器
root.walkRules(function(rule) {
//遍历所有的属性
rule.walkDecls(function(decl) {
//dect 是一个包含属性-值对和一些操作方法的样式对象,最重要的两个属性是decl.prop 属性名和decl.value 属性值.
//过滤包含 overflow , overflow-x , overflow-y 的属性
rule.walkDecls(/^overflow-?/, function(decl) {
if (decl.value === 'scroll') {
//判断是否已经有-webkit-overflow-scrolling,防止重复添加
var hasTouch = rule.some(function(i) {
return i.prop === '-webkit-overflow-scrolling';
});
if (!hasTouch) {
rule.append({
prop: '-webkit-overflow-scrolling',
value: 'touch'
});
}
}
});
});
});
};
});
通过上述插件代码的示例,其实已经可以很清楚的知道编写 PostCss
插件的思路。
- 重点对象是
Root
,Commont
,AtRule
,Rule
,Declaration
,Result
; - 遍历方法,
walkCommonts
,walkAtRules
,walkRules
,walkDels
; - 节点操作(上面的构造函数基本上都有以下类似的操作),
append
,clone
,remove
,toString
。更多操作方法
通过整体梳理,从PostCss
是什么,做什么。到PostCss
插件的使用,以及编写,应该对PostCss
有了整体的认识。PostCss
的API
虽然没有那么复杂,但足够我们做很多事情,让前端工程化玩法更多。示例也只是一个简单的插件代码,还有很多像Autoprefixer
一样优秀的插件,我们甚至可以用PostCss
插件像eslint
一样规范Css
编写。
- 注意事项:
-
postcss-loader
默认使用.postcsssrc.js
文件的配置,postcss.config.js
和.postcsssrc.js
同时存在是会优先使用.postcsssrc.js
中的配置 - 编写
PostCss
插件时,可能会有很多Node
文件操作,请注意同步异步操作的适用情况,避免使用不当,导致产出的css
文件内容错误 -
vue-loader
处理.vue
文件时,如果<style>
标签带有scoped
,那么在经过css-loader > postcss-loader > vue-loader
这一顺序处理后,scoped
标记会在postcss-loader
使用插件产出的css样式运转到vue-loader
处理时在css
和html
标签处添加[data-v-hash码]
,此时postcss-loader
引用的PostCss
插件如果有导出类的操作,可能会导致scoped
失效。并并且没办法在vue-loader
之后再使用postcss
这种思路。只能build
的时候在webpack
构建钩子,在处理完.vue
文件后再处理相关的导出操作,此时是完整的。(此处还有很多细节,具体有问题,可单独私聊。) - 新版的
vue-loader
的api
和老版本的有挺大的差别,请做好甄别。
-
后续看情况更新
有用的网址