新聞中心
最近很火的TailwindCSS有一個(gè)功能:

可以將項(xiàng)目未使用的css選擇器從編譯后css文件中移除。
這個(gè)功能是PurgeCSS實(shí)現(xiàn)的。
鏈接TailwindCSS與PurgeCSS的,則是一個(gè)postCSS插件@fullhuman/postcss-purgecss。
不僅TailwindCSS,還有很多知名項(xiàng)目中使用了postCSS插件。比如:
很多人在項(xiàng)目中使用autoprefixer插件,為css選擇器增加不同的「瀏覽器前綴」。
在其內(nèi)部會(huì)根據(jù)browserslist[1]指定瀏覽器版本。
再去caniuse[2]查找該瀏覽器版本兼容性支持情況。
最后通過(guò)postCSS的能力改寫(xiě)不支持的css屬性。
可以看到,postCSS正越來(lái)越成為前端項(xiàng)目必不可少的依賴(lài)。
同時(shí)也有很多關(guān)于postCSS的誤區(qū),比如認(rèn)為他是和Less、Sass一樣的「css預(yù)處理器」。
本文會(huì)自底向上介紹postCSS,希望通過(guò)此文讓你對(duì)這款大殺器有更深的認(rèn)識(shí)。
什么是postCSS
postCSS是一款css編譯器。
類(lèi)比Babel家族的@babel/parser可以將js代碼解析為AST(抽象語(yǔ)法樹(shù)),再利用眾多插件(@babel/plugin-xx)的能力改寫(xiě)AST,最終輸出改寫(xiě)后的js代碼。
postCSS利用自身的parser可以將css代碼解析為AST,再利用眾多插件(上文介紹的autoprefixer就是一種)改寫(xiě)AST,最終輸出改寫(xiě)后的css代碼。
從這點(diǎn)就能看出其與Less這樣的「css預(yù)處理器」的不同 —— postCSS的輸入與輸出產(chǎn)物都是css文件。
因此,postCSS也被成為「后處理器」,因?yàn)槠渫ǔT赾ss處理鏈條的最后端。
postCSS的AST
你可以在astexplorer[3]中選擇:
- 語(yǔ)言:css
- parser:postCSS
來(lái)了解postCSS如何解析css。
比如,對(duì)于如下css代碼:
- /**
- * I am KaSong
- */
- @media screen and (min-width: 900px) {
- article {
- padding: 1rem 3rem;
- }
- }
- ul {
- margin: 3rem;
- }
- ul li {
- padding: 5px;
- }
會(huì)被postCSS解析為如下樹(shù)結(jié)構(gòu)的AST:
節(jié)點(diǎn)有如下幾種類(lèi)型:
- Root:根節(jié)點(diǎn),代表一個(gè)css文件
- AtRule:以@開(kāi)頭的申明,比如@charset "UTF-8"或@media (screen) {}
- Rule:內(nèi)部包含定義的選擇器,比如input, button {}
- Declaration:key-value鍵值對(duì),比如color: black;
- Comment:?jiǎn)为?dú)的注釋。selectors、at-rule的參數(shù)以及value的注釋在節(jié)點(diǎn)的node屬性?xún)?nèi)
實(shí)現(xiàn)一個(gè)簡(jiǎn)單的插件
接下來(lái)我們從一個(gè)插件的實(shí)現(xiàn)來(lái)了解開(kāi)發(fā)者如何介入postCSS編譯流程。
postcss-focus[4]會(huì)為所有:hover選擇器增加:focus以提高鍵盤(pán)操作的可用性。
對(duì)于如下代碼:
- .a:hover, .b:hover, .c:hover {
- opacity: .5;
- }
經(jīng)過(guò)該插件處理后會(huì)輸出:
- .a:hover, .b:hover, .c:hover, .a:focus, .b:focus, .c:focus {
- opacity: .5;
- }
你可以安裝postcss、postcss-focus后通過(guò)如下demo在控制臺(tái)看到結(jié)果:
- const postcssFocus = require('postcss-focus');
- const postcss = require('postcss');
- const fs = require('fs');
- // 輸入的css文件地址
- const from = 'src/a.css';
- const to = 'output/a.css';
- fs.readFile(from, (err, css) => {
- postcss(postcssFocus).process(css, { from, to }).then(result => {
- console.log(result.css)
- })
- })
接下來(lái)我們分析postcss-focus源碼[5]的實(shí)現(xiàn)邏輯:
- postCSS將輸入的css解析為AST
- 遍歷AST中所有Rule類(lèi)型節(jié)點(diǎn)
- 維護(hù)一個(gè)數(shù)組,遍歷這個(gè)節(jié)點(diǎn)的所有selector,每遍歷到一個(gè)包含:hover的selector就往數(shù)組中push一個(gè):focus的selector
- 將2中得到的數(shù)組concat到該節(jié)點(diǎn)已有的selectors后
- 根據(jù)改變后的AST輸出新的css
核心源碼如下:
- {
- postcssPlugin: 'postcss-focus',
- // 步驟1
- Rule: rule => {
- // 步驟2
- if (rule.selector.includes(':hover')) {
- let focuses = []
- for (let selector of rule.selectors) {
- if (selector.includes(':hover')) {
- let replaced = selector.replace(/:hover/g, ':focus')
- if (!hasAlready(rule.parent, replaced)) {
- focuses.push(replaced)
- }
- }
- }
- // 步驟3
- if (focuses.length) {
- rule.selectors = rule.selectors.concat(focuses)
- }
- }
- }
- }
這個(gè)插件只是為了演示插件的基本工作方法,實(shí)際上該插件實(shí)現(xiàn)的比較粗糙。
postCSS提供了詳細(xì)的插件創(chuàng)建文檔[6]。甚至提供了create-postcss-plugin[7]用來(lái)創(chuàng)建插件的模版代碼。
更多可能性
由于提供了表達(dá)、改寫(xiě)css AST的能力,postCSS的插件可以實(shí)現(xiàn)非常多功能。比如:
postcss-functions
上文介紹了Declaration節(jié)點(diǎn)表達(dá)「css屬性」的鍵值對(duì),其中值為「字符串」類(lèi)型。
那么完全可以自定義值的解析規(guī)則。
- body {
- color: getColor();
- }
通過(guò)定義getColor函數(shù),并在AST中將其解析為函數(shù)執(zhí)行,就能在css文件中用js寫(xiě)邏輯代碼。
這就是postcss-functions[8]
stylelint
配置不同的lint規(guī)則,實(shí)現(xiàn)css的靜態(tài)語(yǔ)法檢測(cè)。這就是stylelint[9]
總結(jié)
當(dāng)前postCSS插件按功能劃分大體有如下幾類(lèi):
- 解決全局css問(wèn)題,比如提供css module[10]支持
- 使用未全面兼容的css特性,比如autoprefixer[11]
- 格式化,提高css可讀性
- 圖片和文字處理
- linters,比如stylelint
- 不同語(yǔ)法的css支持,比如postcss-html[12]可以解析類(lèi)html文件中
讀到這里,相信你會(huì)同意:相比Less、Sass,postCSS才是css處理領(lǐng)域的大殺器。
參考資料
[1]browserslist:
https://github.com/browserslist/browserslist[2]caniuse:
https://caniuse.com/#search=[3]astexplorer:
https://astexplorer.net/[4]postcss-focus:
https://www.npmjs.com/package/postcss-focus[5]postcss-focus源碼:
https://github.com/postcss/postcss-focus/blob/master/index.js[6]插件創(chuàng)建文檔:
https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md[7]create-postcss-plugin:
https://github.com/csstools/create-postcss-plugin[8]postcss-functions:
https://www.npmjs.com/package/postcss-functions[9]stylelint:
https://github.com/stylelint/stylelint[10]css module:
https://github.com/madyankin/postcss-modules[11]autoprefixer:
https://github.com/postcss/autoprefixer[12]postcss-html:
https://github.com/gucong3000/postcss-html
分享名稱(chēng):解剖postCSS-向前端架構(gòu)師邁出一小步
當(dāng)前地址:http://m.5511xx.com/article/dhpioei.html


咨詢(xún)
建站咨詢(xún)
