PostCss
是一個CSS
後處理工具
PostCss
是什麼
首先,聊PostCss
之前,我們得知道什麼是CSS
後處理工具。我們比較熟悉的Less,Sass,Stylus
,這類工具都屬於CSS
預處理工具通過特殊的規則、文本格式最終生成CSS
文件。而PostCss
則是對CSS
進行處理,最終生成CSS
。
多數人最早接觸和使用的應該是Autoprefixer
這款插件,Autoprefixer
的功能是:以 Can I Use 上的 瀏覽器支持數據 爲基礎,自動處理兼容性問題。
# Autoprefixer 處理前的CSS樣式
.container {
display: flex;
}
.item {
flex: 1;
}
# Autoprefixer 處理後的CSS樣式
.container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.item {
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
通過使用Autoprefixer
插件,很大程度上節省了CSS
重複樣式的編寫。Autoprefixer
正是PostCss
衆多插件中的一款,查找更多插件,點這裏。
PostCss
處理Css
過程
作爲一款可安裝使用各類插件的工具,PostCss
提供的API
還是很簡潔明瞭的(吐槽一下Less,什麼鬼玩意兒,API文檔都不寫的)
- 將
Css
文件信息處理成樹型結構的Js
對象。 - 根據配置插件的順序對樹型結構的
Js
對象 進行操作。 - 最終將處理後獲得的樹型結構的
Js
對象輸出爲Css
文件。
那麼關鍵點就在與Css
被處理後生成的樹型結構的Js
對象,那麼先讓我們看一看它的小裙裙裏藏着什麼。
PostCss
處理Css
詳解
- 下圖爲一個很標準的
Css
,有註釋、帶有@
的媒體查詢、以及選擇器樣式。
- 上面的
Css
最終會處理爲下圖結構,通過打印信息我們可以發現樹型結構的Js
對象是一個名爲Root
的構造函數,而起樹型結構的nodes
節點下還有Commont
,AtRule
,Rule
構造函數。
- 上面的
- 樹型結構的
Js
對象在最後會處理成名爲Result
的構造函數,如下圖,帶有css
這個屬性,包含完整的Css
信息,最終會被寫入到文件中。
PostCss
中的各種構造函數
在上面部分關於 PostCss
處理Css
中,生成了很多構造函數。而 PostCss
的神奇功能也都圍繞着這些構造函數,接下來我們一一介紹。
Root
:PostCss
處理過的Css
,整個處理過程基本上都在圍繞着Root
,Commont
,AtRule
,Rule
都是它的子節點。-
Commont
:Css
中的註釋信息,註釋的內容在Commont.text
下。
-
AtRule
: 爲帶@
標識的部分,name
爲標識名稱,params
爲標識參數。nodes
爲內部包含的其他子節點,可以是Commont
,AtRule
,Rule
,這讓我們可以自定義更多的規則,
-
Rule
: 選擇器樣式部分,一個選擇器代表一個Rule
,選擇器對應的樣式列表nodes
爲Declaration
構造函數,
-
Declaration
: 爲Css
樣式屬性,prop
爲樣式屬性,value
爲樣式值。可給Rule
手動添加樣式屬性,也可以修改prop
,value
。上文提到的Autoprefixer
就是通過clone
當前屬性,修改prop
並添加到選擇器下。
Result
: 通過root.toResult()
方法可以獲取到帶有css
全文本信息的Result
對象,也代表這我們PostCss
單個插件到了尾聲。接下來直接將result.css
寫入對應的文件即可。
如何使用 PostCss
插件
PostCss
插件有很多種使用方式,
- 可以配合在
postcss-loader
的options
配置各種插件
plugins: [
themePlugin({}),
autoprefixer({})
]
- 也可以直接在
Node
程序中使用
postcss([themePlugin({})])
.process(css, {from: ``, to: ``})
.then(result => {
// 根據配置文件themeList,分別處理對應的文件,打包各css 文件
})
.catch(error => {
throw new Error(error)
})
如何編寫一個 PostCss
插件
上文中,我們對Css
處理後生成的Root
以及其節點下的Commont
,AtRule
,Rule
, Declaration
有了基本的認識,那麼我們是如何獲得Root
,又將拿這些構造函數做些什麼呢。
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-test-plugin', function (opts) {
opts = opts || {}; // 處理 options
return function (root, result) {
//遍歷所有的選擇器
root.walkRules(function(rule) {
//遍歷所有的屬性
rule.walkDecls(function(decl) {
//dect 是一個包含屬性-值對和一些操作方法的樣式對象,最重要的兩個屬性是decl.prop 屬性名和decl.value 屬性值.
//過濾包含 overflow , overflow-x , overflow-y 的屬性
rule.walkDecls(/^overflow-?/, function(decl) {
if (decl.value === 'scroll') {
//判斷是否已經有-webkit-overflow-scrolling,防止重複添加
var hasTouch = rule.some(function(i) {
return i.prop === '-webkit-overflow-scrolling';
});
if (!hasTouch) {
rule.append({
prop: '-webkit-overflow-scrolling',
value: 'touch'
});
}
}
});
});
});
};
});
通過上述插件代碼的示例,其實已經可以很清楚的知道編寫 PostCss
插件的思路。
- 重點對象是
Root
,Commont
,AtRule
,Rule
,Declaration
,Result
; - 遍歷方法,
walkCommonts
,walkAtRules
,walkRules
,walkDels
; - 節點操作(上面的構造函數基本上都有以下類似的操作),
append
,clone
,remove
,toString
。更多操作方法
通過整體梳理,從PostCss
是什麼,做什麼。到PostCss
插件的使用,以及編寫,應該對PostCss
有了整體的認識。PostCss
的API
雖然沒有那麼複雜,但足夠我們做很多事情,讓前端工程化玩法更多。示例也只是一個簡單的插件代碼,還有很多像Autoprefixer
一樣優秀的插件,我們甚至可以用PostCss
插件像eslint
一樣規範Css
編寫。
- 注意事項:
-
postcss-loader
默認使用.postcsssrc.js
文件的配置,postcss.config.js
和.postcsssrc.js
同時存在是會優先使用.postcsssrc.js
中的配置 - 編寫
PostCss
插件時,可能會有很多Node
文件操作,請注意同步異步操作的適用情況,避免使用不當,導致產出的css
文件內容錯誤 -
vue-loader
處理.vue
文件時,如果<style>
標籤帶有scoped
,那麼在經過css-loader > postcss-loader > vue-loader
這一順序處理後,scoped
標記會在postcss-loader
使用插件產出的css樣式運轉到vue-loader
處理時在css
和html
標籤處添加[data-v-hash碼]
,此時postcss-loader
引用的PostCss
插件如果有導出類的操作,可能會導致scoped
失效。並並且沒辦法在vue-loader
之後再使用postcss
這種思路。只能build
的時候在webpack
構建鉤子,在處理完.vue
文件後再處理相關的導出操作,此時是完整的。(此處還有很多細節,具體有問題,可單獨私聊。) - 新版的
vue-loader
的api
和老版本的有挺大的差別,請做好甄別。
-
後續看情況更新
有用的網址