最近大漠前輩在羣裏發關於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