前言最近大漠前辈在群里发关于PostCSS的系列文章,但是耗子姐姐又说看了有点云里雾里的感觉,所以这篇文章将按一个思考的角度来理解一下 PostCSS 到底是一个什么东西。 
一、提出不懂的地方很多时候第一次在网上查询 PostCSS 概念的时候,大家都解释成一个后处理器的概念,其实个人觉得这些概念不重要,更为重要的有以下几点: 它本质上是一个什么东西? 它能解决我们什么问题? 它是通过什么方式来解决我们的问题? 它解决我们的问题是为什么? 怎么实现与 SASS、LESS、Stylus 相同的功能(因为它们被经常拿来比较) 它由哪些东西组成? 既然是程序可以用的,那么它的API呢?
Q: 这个时候,你应该会问:为什么要将组成和API放到最后呢? A: 那是因为我们在认识一个不太清楚的东西的时候,第一次肯定是一个直观的认识:它到底有什么用?而不会说,一来就去深入的研究它。不过这里本质还是要先说一下的,先留个印象。 二、个个击破1. 它本质上是一个什么东西?为什么说它是一个平台呢?因为我们直接用它,感觉不能干什么事情,但是如果让一些插件在它上面跑,那么将会很强大。
上面两条看完后,我们可以理解为下面这个模型。 
所以说,PostCSS 它需要一个插件系统才能够发挥作用。我们可以通过“插件”来传递AST,然后再把AST转换成一个串,最后再输出到目标文件中去。当然,这里是有API可以用,这里先不讲,免得晕了。 2. 它能解决我们什么问题?它是通过什么方式来解决我们的问题?上面的图很清晰,但是我还是不知道是个什么东西!所以接下来温和点,直接从代码层面来感官的认识一下。 好吧,看到一个熟悉的单词了:autoprefixer,这里我们就让它来当栗子吧,可能更容易理解一点。 首先,我们需要做一些准备,安装好需要的东西。 // postcss 的命令行工具
sudo npm install -g postcss-cli
// autoprefixer 插件
sudo npm install -g autoprefixer
第一次用命令行能让你更直观去理解它哈,所以请要有一颗折腾的心。 // 1. 先看下这个命令有哪些参数可以用
postcss
Usage: /usr/local/bin/postcss -use plugin [
output.css] [input.css]
选项:
-c,
-u,
-o,
-d,
-r,
-s,
-p,
-t,
-w,
-v,
-h,
示例:
postcss
options.json -o screen.css screen.css
postcss
screen.css screen.css
postcss -u postcss-cachify -u Use multiple plugins and multiple
autoprefixer -d build *.css input files
Please specify at least one plugin name.
PS: 我贴出来是方便大家在看的时候不用电脑……^_^ 好吧,先看一下文件目录,这里我只说一下比较好写的方式,就是将一些参数配置到配置文件中去。 
{
"use": ["autoprefixer"],
"input": "src/index.css",
"output": "index.css",
"autoprefixer": {
"browsers": "> 5%"
}
}
{
"autoprefixer": {
"browsers": "> 5%"
}
}
接下来我们在终端里面输入:
postcss -c config.json
postcss -u autoprefixer -c p.json -i src/index.css -o index.css
跟平时想到的效果一样:
// src/index.css 中的源码
`* {
transition: all .1s;
}`
// 转换过后的代码 index.css
`* {
-webkit-transition: all .1s;
transition: all .1s;
}`
好吧,现在肯定就对 PostCSS 有一个感官的认识了,接下来就是需要自己动手去用一下 cssnext 这个插件了~看会发生什么,这里就不写了,也挺好用的,不过应该还是草案状态。 我们开发不可能用命令行吧,所以这里再接着介绍代码编写,然后用 node 去执行文件的方式。直接上代码吧。
npm install postcss --save-dev
npm install autoprefixer --save-dev
var postcss = require('postcss');
var autoprefixer = require('autoprefixer');
var fs = require('fs');
var css = '* { transition: all .1s; }';
postcss([autoprefixer])
.process(css)
.then(function(result) {
console.log(result);
if (result.css) {
fs.writeFileSync('index.css', result.css);
}
if (result.map) {
fs.writeFileSync('index.css.map', result.map);
}
});
node p
好吧,最后的结果和之前用命令行的方式一样,只不过过程不同。这样下来应该对 PostCSS 有了更多的感觉了吧。还没完,不用慌~我们还需要提出一个问题,我都有 SASS 等预处理器了,还拿它来不是又给前端届添乱么?因为这2年东西确实太多了~ 记住一句话:存在即合理
既然合理,那么我们就看看它有什么优势呗~ 3. 它解决我们的问题是为什么?优势何在?比如,我们用 SASS 来处理 box-shadow 的前缀,我们需要这样写:
@mixin box-shadow($top, $left, $blur, $size, $color, $inset: false) {
@if $inset {
-webkit-box-shadow: inset $top $left $blur $size $color;
box-shadow: inset $top $left $blur $size $color;
} @else {
-webkit-box-shadow: $top $left $blur $size $color;
box-shadow: $top $left $blur $size $color;
}
}
使用 PostCSS 我们只需要按标准的 CSS 来写就行了,因为最后 autoprefixer 会帮我们做添加这个事情~ box-shadow: 0 0 3px 5px rgba(222, 222, 222, .3);
所以,这里就出现了一个经常大家说的未来编码的问题。实际上,PostCSS 改变的是一种开发模式。 这样能体会出优势吧,但是目前大家都是 SASS + PostCSS 这样的开发模式,其实我认为是不错的,取长补短嘛,当然,在 PostCSS 平台上都是可以做到的,只是目前这个过渡期,这样更好,更工程化。接下来我就介绍一些方法来纯粹是用 PostCSS。 4. 怎么实现与 SASS、LESS、Stylus 相同的功能其实这一节我都不需要写了~列一下插件就行了,因为插件才是实现,PostCSS 只是提供了一个平台。 其实可以去官方看看:插件系统 这里列几个便于理解的插件 postcss-each postcss-for postcss-mixins postcss-extend
从名字就能看出来了吧~应该很好理解。 5. 它由哪些东西组成?其实从官方介绍来看,只包含以下内容: CSS Parser CSS 节点树 API source map 生成器 生成节点树串
英文不太好 == ,就这 4 部分吧,从第一个图其实也能够看出来。 其中的 I/O 体现在什么地方呢?好吧,很容易想到,主要体现在: Input: 插件程式和CSS Parser Output: 生成节点树串
CSS Parser 可以理解为一个内部过程,而插件程式主要体现在: postcss([ autoprefixer ])
最后生成的节点树串体现在: postcss().process().then(function (result) {
console.log(result.css);
});
var opts = {
from: 'src/index.css',
to: 'index.css',
map: { inline: false }
};
postcss([ autoprefixer, cssnano() ]).process(css, opts)
Result {
processor: Processor {
version: '5.0.10',
plugins: [
[Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object],
[Object], [Object]
]
},
messages: [],
root: Root {
raws: {
semicolon: false,
after: ''
},
type: 'root',
nodes: [
[Object]
],
source: {
input: [Object],
start: [Object]
},
_autoprefixerDisabled: false,
_autoprefixerPrefix: false,
rawCache: {
colon: ':',
indent: '',
beforeDecl: '',
beforeRule: '',
beforeOpen: '',
beforeClose: '',
beforeComment: '',
after: '',
emptyBody: '',
commentLeft: '',
commentRight: ''
}
},
opts: {
from: 'src/index.css',
to: 'index.css'
},
css: '*{-webkit-transition:all .1s;transition:all .1s}',
map:
SourceMapGenerator {
_file: 'index.css',
_sourceRoot: null,
_skipValidation: false,
_sources: ArraySet { _array: [Object], _set: [Object] },
_names: ArraySet { _array: [], _set: {} },
_mappings: MappingList { _array: [Object], _sorted: true, _last: [Object] },
_sourcesContents: { '$src/index.css': '* { transition: all .1s; }' } },
lastPlugin: {
[Function]
postcssPlugin: 'cssnano-reset-stylecache',
postcssVersion: '5.0.10'
}
}
其实吧,这样有点抽象的,还是来看熟悉的 API 吧。 这里出现了 sourcemap,说明 PostCSS 中的转换功能是它必备的,但是必备并不等于:源代码与目标代码不能完全一致。 这里吐槽一下 Chrome 的 sourcemap 功能,一坨屎!下面看看 firefox 里面的效果吧。 
这里 firefox 里面就自动映射了源文件,非常不错! 6. 既然是程序可以用的,那么它的API呢?其实官方有 API 的详细解释,我看了一下,一看就明白了,就不再花时间介绍了,大家可以去看看,这样会知道,原来如此~ PS: 大家可以先看看 Node Common 和 Node相关的,然后再看 plugin 官方API 这里看一个 DEMO,主要做 rem 和 px 单位之间的互换,加入 processors 就可以用了,很方便: var custom = function(css, opts){
css.eachDecl(function(decl){
decl.value = decl.value.replace(/\d+rem/, function(str){
return 16 * parseFloat(str) + "px";
});
});
};
开发插件可以看一下 官方插件指南 更细致的地方,之后有时间的时候再写写 ^_^ 一说技术就停不下来了~ 大家在问?我怎么在工程上应用它呢?好吧,使用 gulp, grunt, webpack 都是可以的,我觉得都理解了 PostCSS ,使用这些就很简单了,一查资料,拷贝一份配置就可以开始用了~就这样吧,下次再结合 react 来介绍一下一个叫: postcss-js 的插件,看上去还不错,还没深入用,用到的时候再分享吧。 其实我也是初学者,只是用了自己的学习方法来梳理成文章,下面都是我看过的文章,部分是引用的。这里就不全部举例了,看的文章有点多。。。 参考的文章大家也可以直接阅读我的博客:http://www.60sky.com
来源:https://segmentfault.com/a/1190000003909268 |