css是web開發中重要的一部分,然而css規範仍存在一些瀏覽器兼容性問題,由此出現了sass、less、stylus等css預處理器,提升了開發人員的效率。javascript
postcss的官方定義:css
A tool for transforming CSS with JavaScript前端
一個用javascript來處理css語法的工具。postcss自己不會對css文件進行修改,它只將css文件轉化爲抽象語法樹(abstract syntax tree,後簡稱ast),而後插件對語法樹進行處理,最後由postcss將ast還原爲普通css,因此postcss對css文件的修改都是基於插件來實現的。java
截止到目前,postcss已有200多個插件,列舉一些比較出名的插件node
autoprefixerwebpack
它從caniuse網站上的數據,自動添加瀏覽器前綴到css中,幫助開發人員解決瀏覽器兼容問題。git
postcss-preset-envgithub
支持css的最新特性,併兼容大多數瀏覽器。web
postcss-modulesshell
模塊化css代碼,爲選擇器提供命名空間後綴。
precss
解析一些類sass語法,包括:變量、嵌套、mixins等。
stylelint
css語法檢查器,能夠幫助開發者檢查css文件中的語法錯誤。
更多插件地址:github.com/postcss/pos…
postcss能夠與各類前端打包工具相結合使用,例如webpack、gulp、grunt、rollup...
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
}
},
{
loader: 'postcss-loader'
}
]
}
]
}
}
// postcss.config.js
module.exports = {
plugins: [
require('precss'),
require('autoprefixer')
]
}
複製代碼
也能夠直接使用postcss提供的js api直接處理css。
const autoprefixer = require('autoprefixer')
const postcss = require('postcss')
const precss = require('precss')
const css = ` .test { color: #fff; } `;
postcss([precss, autoprefixer])
.process(css, { from: 'src/app.css', to: 'dest/app.css' })
.then(result => {
console.log(result.css);
});
複製代碼
開發postcss插件前,首先要理解的一個概念就是文章開頭提到的抽象語法樹,postcss將css文本轉化爲ast,javascript能夠經過一系列api來操做、改變ast,再由解析器將ast解析成普通目標css文本。
css文件:
body {
margin: 0;
}
複製代碼
轉化爲ast,對應的json:
{
"raws": {
"semicolon": false,
"after": ""
},
"type": "root",
"nodes": [
{
"raws": {
"before": "",
"between": " ",
"semicolon": true,
"after": "\n"
},
"type": "rule",
"nodes": [
{
"raws": {
"before": "\n\t",
"between": ": "
},
"type": "decl",
"source": {
"start": {
"line": 2,
"column": 2
},
"input": {
"css": "body {\n\tmargin: 0;\n}",
"id": "<input css 32>"
},
"end": {
"line": 2,
"column": 11
}
},
"prop": "margin",
"value": "0"
}
],
"source": {
"start": {
"line": 1,
"column": 1
},
"input": {
"css": "body {\n\tmargin: 0;\n}",
"id": "<input css 32>"
},
"end": {
"line": 3,
"column": 1
}
},
"selector": "body"
}
],
"source": {
"input": {
"css": "body {\n\tmargin: 0;\n}",
"id": "<input css 32>"
},
"start": {
"line": 1,
"column": 1
}
}
}
複製代碼
其中,ast的第一級是一個root類型的節點,type除root外還包括rule、decl、atrule、comment,nodes屬性表示節點下的子節點。
postcss爲咱們提供了一些基本的ast操做方法:
更多節點信息參照postcss api文檔:api.postcss.org/
咱們開發一個將像素值乘以2的插件。
const postcss = require('postcss');
const postcssPluginParseMargin = postcss.plugin('postcss-parse-margin', function(){
return function(root){
root.walkDecls(function(decl){
decl.value = decl.value.replace(/(\d*\.?\d+)\s*px/, function(match, numStr) {
return Number(numStr) * 2 + 'px';
});
});
}
});
const css = ` .test { font-size: 2.5px; } `;
postcss([postcssPluginParseMargin]).process(css).then(function(res){
console.log(res.css);
});
/** .test { font-size: 5px; } */
複製代碼
咱們調用walkDecls函數,從root節點開始遍歷全部的decl類型節點,取出decl.value中的像素值,乘以2後替換掉原有decl.value,這樣就實現了一個簡單的postcss插件。
less是一種css預處理器,爲css擴展了更多的功能,如變量、繼承、mixins、函數等。若是咱們想基於less的語法使用postcss的插件,一種方案是使用less將less語法轉義成css語法後,再用postcss處理轉義後的css文件,但這種方案因爲要經歷兩次語法樹的生成過程,比較耗時。與sass不一樣,less自己就是js編寫的,所以咱們能夠基於less自帶的語法樹解析器,將less語法樹直接轉化爲postcss語法樹,就能夠無縫銜接使用其餘postcss插件。
這個輪子已經有大神幫咱們造好,叫作postcss-less-engin,只是項目已有一年多未更新,less仍是基於2.7.1版本,更新到3.0.0以上會報錯。查閱了less的changelog,發現緣由是3.0.0之後,less解析器中的Directive類重命名爲AtRule,Rule重命名爲Declaration。bug修復好已提pr等待做者更新,你們若有須要支持最新less能夠暫時使用postcss-less-engine-latest,git地址:github.com/Crunch/post…
插件用法:
const postcss = require('postcss');
const postCssLessEngine = require('postcss-less-engine');
const css = ` @color: red; .test { color: @color; } `;
postcss([
postCssLessEngine()
]).process(
css, {
parser: postCssLessEngine.parser
}
).then((result)=>{
console.log(result.css);
/** .test { color: red; } */
});
複製代碼
若是隻想支持less的部分特性,徹底能夠本身編寫postcss插件來支持,postcss-less插件能夠用來識別less語法,爲postcss抽象語法樹添加less標識,可是不會轉換原有代碼,轉換工做交給其餘postcss插件來完成,你們有興趣能夠開發適合本身需求的插件。
git地址:github.com/shellscape/…