在 CSS 预编译器之后:PostCSS
提到 css 预编译器(css preprocessor),你可能想到 Sass[]以及[Stylus][]。而本文要介绍的 PostCSS,正是一个这样的工具:css 预编译器可以做到的事,它同样可以做到。
你说的我都懂,那为什么要用它?
套装与单件
如果 Sass 等预编译器是新定义了一种模板语言,然后将其转化为 css 的话,[PostCSS][]则是更纯粹地对 css 本身做转换。
回想一下你是如何学习使用 css 预编译器的:了解到有这样一种可以转化为 css 的语言,它有很多特性,变量、嵌套、继承等等,每一种特性都通过一定语法实现。大概就像是递给你一个已经封装好的工具箱(量产型?),你可以在里面找有用的东西。
那 PostCSS 是怎样呢?PostCSS 就像只递给你一个盒子,但告诉你你可以从旁边的陈列柜取走自己想要的工具放进盒子打包带走。如果你觉得陈列柜里的不够好,PostCSS 还可以帮你打造你自己的工具。所以,使用 PostCSS,你可以仅取所需。
这就是 PostCSS 的 模块化 ( modular )风格。它作为一个 css 转换工具,自身很小,其所有的转换功能都是插件,因此可以个性化配置。
PostCSS 的简要原理
PostCSS 自身只包括 css 分析器,css 节点树 API,source map 生成器以及 css 节点树拼接器。
css 的组成单元是一条一条的样式规则(rule),每一条样式规则又包含一个或多个属性&值的定义。所以,PostCSS 的执行过程是,先 css 分析器读取 css 字符内容,得到一个完整的节点树,接下来,对该节点树进行一系列转换操作(基于节点树 API 的插件),最后,由 css 节点树拼接器将转换后的节点树重新组成 css 字符。期间可生成 source map 表明转换前后的字符对应关系:
比较有意思的是,PostCSS 的插件其实都是 JavaScript 函数,它们使用 PostCSS 的节点树 API,对 css 节点树进行不同的转换。
插件预览
所有插件都可以在[PostCSS 的主页][]中查询到,这里只选取一小部分示意一下。
Autoprefixer
PostCSS 最有名的插件是 Autoprefixer[]及你设定的浏览器支持范围,因此相当可靠。下面是一个示例(以我设定的浏览器支持范围):
.container{
display: flex;
}
编译后:
.container{
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
postcss-nested&postcss-mixins
在刚开始使用 PostCSS 时,我就想到要用 PostCSS 实现我在 Sass 中最常用的特性。所以,我找到了 postcss-nested
和 postcss-mixins
。将它们结合起来后,就可以做到这样:
@define-mixin clearfix{
&:after{
display: table;
clear: both;
content: " ";
}
}
.column-container{
color: #333;
@mixin clearfix;
}
编译后:
.column-container{
color: #333;
}
.column-container:after{
display: table;
clear: both;
content: " ";
}
到这里,你是否已经有了“预编译器可以做到的它也可以做到”的感觉呢?
如何使用 PostCSS
我个人推荐结合 Gulp[]的用法。
gulp-postcss
及插件都是[npm][],首先,使用 npm install
将它们分别安装到项目目录中(会位于 node_modules
)。然后,编辑 glupfile.js
,将 PostCSS 注册为 Gulp 的一个任务。以下是一个结合使用了 Autoprefixer
、 postcss-simple-vars
、 postcss-mixins
、 postcss-nested
4 个插件,且生成 source map 文件的例子:
var gulp = require("gulp");
var postcss = require("gulp-postcss");
var autoprefixer = require('autoprefixer-core');
var postcssSimpleVars = require("postcss-simple-vars");
var postcssMixins = require("postcss-mixins");
var postcssNested = require("postcss-nested");
var sourcemaps = require("gulp-sourcemaps");
// Css process.
gulp.task("postcss", function(){
var processors = [
postcssMixins,
postcssSimpleVars,
postcssNested,
autoprefixer({
browsers: ["Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 10"]
})];
return gulp.src(["./stylesheets/src/*.css"])
.pipe(sourcemaps.init())
.pipe(postcss(processors))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("./stylesheets/dest"));
});
在上面这段代码中, processors
是一个数组,定义了用到的 PostCSS 插件。PostCSS 会按照定义顺序依次执行插件,因此,在结合多个插件使用时,请注意它们的位置。
自定义转换
此外,你可以很容易地创建你自己的转换(还记得前面说过 PostCSS 的插件都是 JavaScript 函数吧?)。例如,下面是一个自定义的转换方法,它将 css 代码中的带有 rem
单位的值,更改为 px
的值。
var custom = function(css, opts){
css.eachDecl(function(decl){
decl.value = decl.value.replace(/\d+rem/, function(str){
return 16 * parseFloat(str) + "px";
});
});
};
然后,你将这个方法直接添加到 processors
中(就像 postcssMixins
那些那样)就可以使用。如果原来有值是 3rem
,将变成 48px
。
以上只是一个简单的转换,如果要正式做一个插件,请参考[PostCSS 插件指南][]。
性能
PostCSS 宣称,由 JavaScript 编写的 PostCSS 比 C++编写的[libsass][](Sass 原本是 Ruby 编写的,但后来出了 C++的引擎,也就是 libsass,它更快)还要快 3 倍。这里的具体数字我觉得不用多关心,可以感受到“PostCSS 的运行速度很快”就足够了。
实际运行起来大概这样:
做到更多
基于 PostCSS,可以做到许多现有的 css 预编译器做不到的事。例如,插件系列[cssnext][]可以让你使用 CSS4+的语法(增加了变量等许多特性),它会帮你转化为目前可用的 CSS3。
一点问题
PostCSS 有一个问题,那就是它是零散的,所以我无法找到一个编辑器能正确地解析并高亮准备使用 PostCSS 的 css 代码。例如在 WebStorm 中我把它当做普通的 css 文件,结果就会收到很多红色的错误提示。
所以,css 预编译器过时了吗?
当然不会。就像其他流行的框架和工具那样,css 预编译器是已经验证过的可用工具,我们完全可以根据需要选用。
Sass 等 css 预编译器的特点是成熟可靠。一方面,它们已经是流行的模板语言,有完善的文档和周边支持,相对稳定,新加入团队的人也能比较容易地理解。另一方面,集成的风格有它的方便之处,就像你可能会懒得去组装一个模型,但能找到专业的人替你完成。
PostCSS 的特点则是模块化。从长远来看,PostCSS 可以做到更多类型的 css 转换。而可定制的风格非常适合追求个性的人(更快捷,而且可以自己做出很有趣的插件)。
此外,css 预编译器和 PostCSS 可以协同使用。有一个流行的用法就是 Sass 编译后再接 PostCSS 的 Autoprefixer
(毕竟这是 PostCSS 的招牌插件)。
结语
PostCSS 的风格可以说是在打造一个改变 css 开发方式的生态系统。所以如果说到未来,还是挺期待的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论