之前,我们在 SitePoint 上多次特刊了 PostCSS 内容,但它还是难倒了很多人。一句话总结 PostCSS:
PostCSS 处理了很多你不必处理的乏味工作
它很巧妙的不同于预处理器,提供了可选的且更简洁的编程语言,来编译成 CSS,如 Sass、Less 与 Stylus。得出这个结论的部分原因是:
- 它的名字。PostCSS 既能在预处理器将源代码编译成 CSS 之前也能在其之后对文件执行操作。
- PostCSS _能_替代你的预处理器。现在有很多插件实现了一些设计,如变量、 嵌套、mixins 以及 extends。
然而,虽然你可以构建自己的预处理器,但除非你想限制功能并加快编译速度,你没有别的该这么做的理由。就我个人而言,为增强 CSS,我使用 Sass,再加以 PostCSS 辅佐。
如何使用 PostCSS?
PostCSS 能在独立的 JavaScript 文件中使用,也能在 Gulp,Grunt,Broccoli,Brunch 还有很多我都没听过的任务运行器中使用
PostCSS 本身只负责将 CSS 解析为 JavaScript 对象与词元(token)。那些检查、修改、添加或修改属性与属性值的插件的魔法发生在写最终 CSS 文件之前。
为了在 Gulp 中使用 PostCSS,你需要建立你的项目并安装两个模块:
npm init npm install --save-dev gulp gulp-postcss复制代码
然后,你可以继续添加你需要的插件,如: autoprefixer 与 cssnano。
npm install --save-dev autoprefixer cssnano复制代码
你可以创建一个 gulpfile.js 文件。它定义了一个任务,加载 CSS 源文件然后通过 PostCSS 管道。插件以及任意所需的其它选项以一个数组传给 PostCSS。最终,CSS 文件被输出至目标文件。
// Gulp.js 配置var gulp = require('gulp'), postcss = require('gulp-postcss');// 应用 PostCSS 插件gulp.task('css', function() { return gulp.src('src/main.css') .pipe(postcss([ require('autoprefixer')({}), require('cssnano') ])) .pipe(gulp.dest('dest/main.css')); });复制代码
在控制台,可使用下面的命令运行该任务:
gulp css复制代码
现在我们只差一份方便的 PostCSS 插件列表了。
1. Autoprefixer
如果你不用其它插件,安装 Autoprefixer。
npm install --save-dev autoprefixer复制代码
随着浏览器对规范的支持越来越好,供应商选择替代方案如基于标记的属性使能,特定浏览器前缀如 -webkit-、 -moz- 以及 -ms- 正逐渐消亡。不幸的是,你还无法避免使用供应商前缀,但你很难知道哪些前缀是一直需要的(例如 user-select),哪些是偶尔需要的(例如 3D 转换),哪些是从不需要的(例如 border-radius)。
有了 Autoprefixer,你不再需要担心前缀选择了。你只需要定义无前缀的 CSS,然后声明你想支持的浏览器,Autoprefixer 将在添加必要前缀时查询检查 caniuse.com。下面的代码指定了任意主流浏览器最新的 2 个版本,或者任何市场占有率超过了 2% 的浏览器:
.pipe(postcss([ require('autoprefixer')({browsers: ['last 2 versions', '> 2%'] }) ]))复制代码
在预处理器的库函数中,这是一个高级选项,要求特殊的编码方式,且会在任意情况下都应用供应商前缀。随着浏览器标准的进化,在未来运行 PostCSS 时,你添加了前缀的代码将会被移除。
Autoprefixer 非常有用并广为流畅,可能你已经正在使用它却没有意识到它是一个 PostCSS 插件。
2. PostCSS Assets
PostCSS Assets 提供了很多实用的图像处理函数:
npm install --save-dev postcss-assets复制代码
它的选项包括:
- 归约 URL: 通过给定文件名,PostCSS Assets 会使用根路径或完全合法的 URL 来替换 resolve(image)。
- 处理尺寸: PostCSS Assets 会使用一个等价的像素值来替换 width(image), height(image) 或 size(image)。
- 内联图像: PostCSS Assets 会使用 Base64 编码的字符串替换 inline(image)。
- 清除缓存: PostCSS Assets 会给图像引用添加一个随机的查询字符串来确认加载的是最新的文件。
3. cssnext
cssnext 让你现在就能使用最新的 CSS 语法。
npm install --save-dev postcss-cssnext复制代码
这个插件有份很长的特性列表,包括:
- var 变量
- #rrggbbaa 颜色
- 颜色函数
- 过滤器
- 回退
当它执行时,cssnext 会将代码翻译成现在的浏览器支持的语法。
4. Rucksack
Rucksack 提供了很多函数,它的开发者宣称,它们会使 CSS 开发再次有趣起来。
npm install --save-dev rucksack-css复制代码
它的选项包括:
- 响应式的字体排版,仅需一个简单的 font-size: responsive 声明,就能够自动调整字体大小与行高。
- 大量伪选择器,如 li:at-least(4),选择了任意含至少 4 个条目的列表。
- 属性别名,如在你的 CSS 中使用 bg 代替 background,
- 大量预定义的缓动函数。
5. Stylelint
Stylelint 基于 140 个规则报错,这些规则被设计用来捕获常见错误,实现样式协议并强制最佳实践。有很多选项可用来依你的喜好配置 Stylelint —— Pavels Jelisejevs 的文章使用 PostCSS 提升你的 CSS 质量带你走过搭建过程。
6. CSS MQPacker
MQPacker 在必要时会将你的媒体查询成一个规则:
npm install --save-dev css-mqpacker复制代码
预处理器如 Sass 能在一个声明里使用媒体查询,很简单,如:
.widget1 { width: 100%; @media (min-width: 30em) { width: 50%; } @media (min-width: 60em) { width: 25%; } } .widget2 { width: 100px; @media (min-width: 30em) { width: 200px; } }复制代码
这会编译成:
.widget1 { width: 100%; }@media (min-width: 30em) { .widget1 { width: 50%; } }@media (min-width: 60em) { .widget1 { width: 25%; } }.widget2 { width: 100px; }@media (min-width: 30em) { .widget2 { width: 200px; } }复制代码
为了减小文件大小以及(尽可能)提升解析时间,MQPacker 会将多个声明打包到一个 @media 规则中,也就是:
.widget1 { width: 100%; }.widget2 { width: 100px; }@media (min-width: 30em) { .widget1 { width: 50%; } .widget2 { width: 200px; } }@media (min-width: 60em) { .widget1 { width: 25%; } }复制代码
可靠情报:确保你的代码中第一个媒体查询声明按照你所想的顺序定义了所有可能的选项,即使没有实际的不同。这能保证 MQPacker 会以正确的顺序定义规则。
MQPacker 也提供了选项来排序媒体查询与输出 sourcemap。
7. cssnano
cssnano 会压缩你的 CSS 文件来确保在开发环境中下载量尽可能的小。通过下面的命令安装它:
npm install --save-dev cssnano复制代码
这个插件通过移除注释、空白、重复规则、过时的浏览器前缀以及做出其他的优化来工作,一般能减少至少 50% 的大小。还有很多其它选择,但 cssnano 是其中最好的一个。使用它!
还有什么?
postcss.parts 上提供了可搜索的 PostCSS 插件索引, PostCSS 使用文档 也提供了建议的选项列表。几乎任何你能想到的 CSS 工作都能找到插件,但注意存在的交叉与重复的问题 —— 例如,cssnext 也包括 Autoprefixer。
如果那还不够的话,你还可以用 JavaScript 开发你自己的 PostCSS 插件。PostCSS 文档讲解了如何写一个插件并提供了一份参考 API。
不管你是否使用预处理器,PostCSS 都使得 CSS 开发变得更简单了。它节省的 CSS 开发时间比为最初的安装与配置付出的努力重要多了。