<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          解剖postCSS —— 向前端架構(gòu)師邁出一小步

          共 5196字,需瀏覽 11分鐘

           ·

          2021-03-20 11:54


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

          可以將項(xiàng)目未使用的css選擇器從編譯后css文件中移除。

          這個(gè)功能是PurgeCSS實(shí)現(xiàn)的。

          鏈接TailwindCSSPurgeCSS的,則是一個(gè)postCSS插件@fullhuman/postcss-purgecss。

          不僅TailwindCSS,還有很多知名項(xiàng)目中使用了postCSS插件。比如:

          很多人在項(xiàng)目中使用autoprefixer插件,為css選擇器增加不同的「瀏覽器前綴」。

          在其內(nèi)部會(huì)根據(jù)browserslist[1]指定瀏覽器版本。

          再去caniuse[2]查找該瀏覽器版本兼容性支持情況。

          最后通過postCSS的能力改寫不支持的css屬性。

          可以看到,postCSS正越來越成為前端項(xiàng)目必不可少的依賴。

          同時(shí)也有很多關(guān)于postCSS的誤區(qū),比如認(rèn)為他是和Less、Sass一樣的「css預(yù)處理器」。

          本文會(huì)自底向上介紹postCSS,希望通過此文讓你對(duì)這款大殺器有更深的認(rèn)識(shí)。

          什么是postCSS

          postCSS是一款css編譯器。

          類比Babel家族的@babel/parser可以將js代碼解析為AST(抽象語法樹),再利用眾多插件(@babel/plugin-xx)的能力改寫AST,最終輸出改寫后的js代碼。

          postCSS利用自身的parser可以將css代碼解析為AST,再利用眾多插件(上文介紹的autoprefixer就是一種)改寫AST,最終輸出改寫后的css代碼。

          從這點(diǎn)就能看出其與Less這樣的「css預(yù)處理器」的不同 —— postCSS的輸入與輸出產(chǎn)物都是css文件。

          因此,postCSS也被成為「后處理器」,因?yàn)槠渫ǔT?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">css處理鏈條的最后端。

          postCSS的AST

          你可以在astexplorer[3]中選擇:

          • 語言:css

          • parser:postCSS

          來了解postCSS如何解析css

          比如,對(duì)于如下css代碼:

          /**
           * I am KaSong
           */


          @media screen and (min-width: 900px) {
            article {
              padding1rem 3rem;
            }
          }


          ul {
           margin3rem;
          }

          ul li {
           padding5px;
          }

          會(huì)被postCSS解析為如下樹結(jié)構(gòu)的AST

          節(jié)點(diǎn)有如下幾種類型:

          • Root:根節(jié)點(diǎn),代表一個(gè)css文件

          • AtRule:以@開頭的申明,比如@charset "UTF-8"@media (screen) {}

          • Rule:內(nèi)部包含定義的選擇器,比如input, button {}

          • Declaration:key-value鍵值對(duì),比如color: black;

          • Comment:單獨(dú)的注釋。selectors、at-rule的參數(shù)以及value的注釋在節(jié)點(diǎn)的node屬性內(nèi)

          實(shí)現(xiàn)一個(gè)簡單的插件

          接下來我們從一個(gè)插件的實(shí)現(xiàn)來了解開發(fā)者如何介入postCSS編譯流程。

          postcss-focus[4]會(huì)為所有:hover選擇器增加:focus以提高鍵盤操作的可用性。

          對(duì)于如下代碼:

          .a:hover.b:hover.c:hover {
            opacity: .5;
          }

          經(jīng)過該插件處理后會(huì)輸出:

          .a:hover.b:hover.c:hover.a:focus.b:focus.c:focus {
            opacity: .5;
          }

          你可以安裝postcss、postcss-focus后通過如下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)
            })
            
          })

          接下來我們分析postcss-focus源碼[5]的實(shí)現(xiàn)邏輯:

          1. postCSS將輸入的css解析為AST

          2. 遍歷AST中所有Rule類型節(jié)點(diǎn)

          3. 維護(hù)一個(gè)數(shù)組,遍歷這個(gè)節(jié)點(diǎn)的所有selector,每遍歷到一個(gè)包含:hoverselector就往數(shù)組中push一個(gè):focusselector

          4. 將2中得到的數(shù)組concat到該節(jié)點(diǎn)已有的selectors

          5. 根據(jù)改變后的AST輸出新的css

          核心源碼如下:

          {
            postcssPlugin'postcss-focus',
            // 步驟1
            Rulerule => {
              // 步驟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]用來創(chuàng)建插件的模版代碼。

          更多可能性

          由于提供了表達(dá)、改寫css AST的能力,postCSS的插件可以實(shí)現(xiàn)非常多功能。比如:

          postcss-functions

          上文介紹了Declaration節(jié)點(diǎn)表達(dá)「css屬性」的鍵值對(duì),其中值為「字符串」類型。

          那么完全可以自定義值的解析規(guī)則。

          body {
            colorgetColor();
          }

          通過定義getColor函數(shù),并在AST中將其解析為函數(shù)執(zhí)行,就能在css文件中用js寫邏輯代碼。

          這就是postcss-functions[8]

          stylelint

          配置不同的lint規(guī)則,實(shí)現(xiàn)css的靜態(tài)語法檢測。這就是stylelint[9]

          總結(jié)

          當(dāng)前postCSS插件按功能劃分大體有如下幾類:

          • 解決全局css問題,比如提供css module[10]支持

          • 使用未全面兼容的css特性,比如autoprefixer[11]

          • 格式化,提高css可讀性

          • 圖片和文字處理

          • linters,比如stylelint

          • 不同語法的css支持,比如postcss-html[12]可以解析類html文件中<style>標(biāo)簽內(nèi)的css語法

          讀到這里,相信你會(huì)同意:相比LessSass,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



          愛心三連擊

          1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的在看是我創(chuàng)作的動(dòng)力。

          2.關(guān)注公眾號(hào)腦洞前端,獲取更多前端硬核文章!加個(gè)星標(biāo),不錯(cuò)過每一條成長的機(jī)會(huì)。

          3.如果你覺得本文的內(nèi)容對(duì)你有幫助,就幫我轉(zhuǎn)發(fā)一下吧。


          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉熟女 | 美女扒开腿秘 免费视频 | www.国产三级 | 一级爱ai高清免费在线视频 | 久久久久理论 |