最近大漠前辈在群里发关于PostCSS
的系列文章,可是耗子姐姐又说看了有点云里雾里的感受,因此这篇文章将按一个思考的角度来理解一下 PostCSS 究竟是一个什么东西。javascript
不少时候第一次在网上查询 PostCSS 概念的时候,你们都解释成一个后处理器
的概念,其实我的以为这些概念不重要,更为重要的有如下几点:css
SASS
、LESS
、Stylus
相同的功能(由于它们被常常拿来比较)Q: 这个时候,你应该会问:为何要将组成和API放到最后呢?html
A: 那是由于咱们在认识一个不太清楚的东西的时候,第一次确定是一个直观的认识:它到底有什么用?而不会说,一来就去深刻的研究它。不过这里本质仍是要先说一下的,先留个印象。前端
平台、平台、平台
,重要的事情来三遍比较爽,哈哈!为何说它是一个平台呢?由于咱们直接用它,感受不能干什么事情,可是若是让一些插件在它上面跑,那么将会很强大。java
上面两条看完后,咱们能够理解为下面这个模型。node
因此说,PostCSS 它须要一个插件系统才可以发挥做用。咱们能够经过“插件”来传递AST,而后再把AST转换成一个串,最后再输出到目标文件中去。固然,这里是有API能够用,这里先不讲,省得晕了。react
上面的图很清晰,可是我仍是不知道是个什么东西!因此接下来温和点,直接从代码层面来感官的认识一下。webpack
平台
上,咱们可以开发一些插件,来处理咱们的CSS,好比热门的:autoprefixer好吧,看到一个熟悉的单词了:autoprefixer,这里咱们就让它来当栗子吧,可能更容易理解一点。git
首先,咱们须要作一些准备,安装好须要的东西。github
// postcss 的命令行工具 sudo npm install -g postcss-cli // autoprefixer 插件 sudo npm install -g autoprefixer
第一次用命令行能让你更直观去理解它哈,因此请要有一颗折腾的心。
// 1. 先看下这个命令有哪些参数能够用 postcss --help Usage: /usr/local/bin/postcss -use plugin [--config|-c config.json] [--output|-o output.css] [input.css] 选项: -c, --config JSON file with plugin configuration -u, --use postcss plugin name (can be used multiple times) -o, --output Output file (stdout if not provided) -d, --dir Output directory -r, --replace Replace input file(s) with generated output [boolean] -s, --syntax Alternative input syntax parser -p, --parser Alternative CSS parser -t, --stringifier Alternative output stringifier -w, --watch auto-recompile when detecting source changes -v, --version 显示版本号 [boolean] -h, --help 显示帮助信息 [boolean] 示例: postcss --use autoprefixer -c Use autoprefixer as a postcss plugin options.json -o screen.css screen.css postcss --use autoprefixer Pass plugin parameters in --autoprefixer.browsers "> 5%" -o plugin.option notation 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: 我贴出来是方便你们在看的时候不用电脑……^_^
好吧,先看一下文件目录,这里我只说一下比较好写的方式,就是将一些参数配置到配置文件中去。
// config.json: 全部的配置 // p.json: 仅有 autoprefixer 插件的配置 // config.json 的内容 { "use": ["autoprefixer"], "input": "src/index.css", "output": "index.css", "autoprefixer": { "browsers": "> 5%" } }
// p.json 的内容 { "autoprefixer": { "browsers": "> 5%" } }
接下来咱们在终端里面输入:
// 最简洁的方式 postcss -c config.json // 稍微复杂一点的方式,这里要用 -i 参数,help里面没有,我是从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 去执行文件的方式。直接上代码吧。
// 1. 先安装一下须要的库 npm install postcss --save-dev npm install autoprefixer --save-dev
// 2. 其实应该先看看 postcss 的 package.json 文件,来看看包含了些什么,留个印象 // 3. p.js 中的代码 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); } });
// 4. 执行 p.js node p
好吧,最后的结果和以前用命令行的方式同样,只不过过程不一样。这样下来应该对 PostCSS 有了更多的感受了吧。还没完,不用慌~咱们还须要提出一个问题,我都有 SASS
等预处理器了,还拿它来不是又给前端届添乱么?由于这2年东西确实太多了~
记住一句话:存在即合理
既然合理,那么咱们就看看它有什么优点呗~
好比,咱们用 SASS 来处理 box-shadow 的前缀,咱们须要这样写:
/* CSS3 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。
其实这一节我都不须要写了~列一下插件就好了,由于插件才是实现,PostCSS 只是提供了一个平台。
其实能够去官方看看:插件系统 这里列几个便于理解的插件
从名字就能看出来了吧~应该很好理解。
其实从官方介绍来看,只包含如下内容:
英文不太好 == ,就这 4 部分吧,从第一个图其实也可以看出来。
其中的 I/O 体如今什么地方呢?好吧,很容易想到,主要体如今:
CSS Parser 能够理解为一个内部过程,而插件程式主要体如今:
postcss([ autoprefixer ])
最后生成的节点树串体如今:
postcss().process().then(function (result) { // 就是这里了 console.log(result.css); }); // 如今我贴一下上面 result 对象的一个输出结果 // 这里我多引入了一个 cssnano 插件 // 改变的代码就这点,为了更全的看 result var opts = { from: 'src/index.css', to: 'index.css', // 配置 map 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 变量 opts: { from: 'src/index.css', to: 'index.css' }, // 这就是从新生成的 节点树串 // 这里有自动补全和高效压缩的效果 css: '*{-webkit-transition:all .1s;transition:all .1s}', // map的文件的配置 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 里面就自动映射了源文件,很是不错!
其实官方有 API 的详细解释,我看了一下,一看就明白了,就再也不花时间介绍了,你们能够去看看,这样会知道,原来如此~
PS: 你们能够先看看 Node Common 和 Node相关的,而后再看 plugin
这里看一个 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 的插件,看上去还不错,还没深刻用,用到的时候再分享吧。
其实我也是初学者,只是用了本身的学习方法来梳理成文章,下面都是我看过的文章,部分是引用的。这里就不所有举例了,看的文章有点多。。。
https://github.com/postcss/postcss
http://rapheal.sinaapp.com/category/js/uglify%E6%BA%90%E7%A0%81/
http://www.w3cplus.com/blog/tags/517.html
http://acgtofe.com/posts/2015/05/modular-transforming-with-postcss/
http://www.oschina.net/translate/its-time-for-everyone-to-learn-about-postcss?cmp