PostCSS是個什麼鬼東西?

前言

最近大漠前輩在羣裏發關於PostCSS的系列文章,可是耗子姐姐又說看了有點雲裏霧裏的感受,因此這篇文章將按一個思考的角度來理解一下 PostCSS 究竟是一個什麼東西。javascript

輸入圖片說明

1、提出不懂的地方

不少時候第一次在網上查詢 PostCSS 概念的時候,你們都解釋成一個後處理器的概念,其實我的以爲這些概念不重要,更爲重要的有如下幾點:css

  1. 它本質上是一個什麼東西?
  2. 它能解決咱們什麼問題?
  3. 它是經過什麼方式來解決咱們的問題?
  4. 它解決咱們的問題是爲何?
  5. 怎麼實現與 SASSLESSStylus 相同的功能(由於它們被常常拿來比較)
  6. 它由哪些東西組成?
  7. 既然是程序能夠用的,那麼它的API呢?

Q: 這個時候,你應該會問:爲何要將組成和API放到最後呢?html

A: 那是由於咱們在認識一個不太清楚的東西的時候,第一次確定是一個直觀的認識:它到底有什麼用?而不會說,一來就去深刻的研究它。不過這裏本質仍是要先說一下的,先留個印象。前端


2、個個擊破

1. 它本質上是一個什麼東西?

  • PostCSS 能夠直觀的理解爲:它就是一個平臺、平臺、平臺,重要的事情來三遍比較爽,哈哈!

爲何說它是一個平臺呢?由於咱們直接用它,感受不能幹什麼事情,可是若是讓一些插件在它上面跑,那麼將會很強大。java

  • PostCSS 提供了一個解析器,它可以將 CSS 解析成抽象語法樹(AST)。

上面兩條看完後,咱們能夠理解爲下面這個模型。node

輸入圖片說明

因此說,PostCSS 它須要一個插件系統纔可以發揮做用。咱們能夠經過「插件」來傳遞AST,而後再把AST轉換成一個串,最後再輸出到目標文件中去。固然,這裏是有API能夠用,這裏先不講,省得暈了。react

2. 它能解決咱們什麼問題?它是經過什麼方式來解決咱們的問題?

上面的圖很清晰,可是我仍是不知道是個什麼東西!因此接下來溫和點,直接從代碼層面來感官的認識一下。webpack

  • 它可以爲 CSS 提供額外的功能;
  • 經過在 PostCSS 這個平臺上,咱們可以開發一些插件,來處理咱們的CSS,好比熱門的:autoprefixer
  • 咱們可以使用JavaScript來開發插件(這點對前端來講很重要)

好吧,看到一個熟悉的單詞了: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年東西確實太多了~

記住一句話:存在即合理

既然合理,那麼咱們就看看它有什麼優點唄~

3. 它解決咱們的問題是爲何?優點何在?

好比,咱們用 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等工具:源代碼 -> 生產環境 CSS
  • PostCSS:源代碼 -> 標準 CSS -> 生產環境 CSS

這樣能體會出優點吧,可是目前你們都是 SASS + PostCSS 這樣的開發模式,其實我認爲是不錯的,取長補短嘛,固然,在 PostCSS 平臺上都是能夠作到的,只是目前這個過渡期,這樣更好,更工程化。接下來我就介紹一些方法來純粹是用 PostCSS。

4. 怎麼實現與 SASS、LESS、Stylus 相同的功能

其實這一節我都不須要寫了~列一下插件就好了,由於插件纔是實現,PostCSS 只是提供了一個平臺。

其實能夠去官方看看:插件系統 這裏列幾個便於理解的插件

  • postcss-each
  • postcss-for
  • postcss-mixins
  • postcss-extend

從名字就能看出來了吧~應該很好理解。

5. 它由哪些東西組成?

其實從官方介紹來看,只包含如下內容:

  1. CSS Parser
  2. CSS 節點樹 API
  3. source map 生成器
  4. 生成節點樹串

英文不太好 == ,就這 4 部分吧,從第一個圖其實也可以看出來。

其中的 I/O 體如今什麼地方呢?好吧,很容易想到,主要體如今:

  • Input: 插件程式CSS Parser
  • Output: 生成節點樹串

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 裏面就自動映射了源文件,很是不錯!

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 的插件,看上去還不錯,還沒深刻用,用到的時候再分享吧。

其實我也是初學者,只是用了本身的學習方法來梳理成文章,下面都是我看過的文章,部分是引用的。這裏就不所有舉例了,看的文章有點多。。。

7. 參考的文章

  • 最權威的初認識

https://github.com/postcss/postcss

  • 一個不錯的東西 rework

https://github.com/reworkcss

  • 理解 AST 等插件解析技術

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

  • 一個開發模式簡單的優劣比較

http://caibaojian.com/css-processor.html

相關文章
相關標籤/搜索