快速入門 Postcss 插件:自動轉(zhuǎn)換 Px 到 Rem
postcss 是 css 的 transpiler,它對于 css 就像 babel 對于 js 一樣,能夠做 css 代碼的分析和轉(zhuǎn)換。同時,它也提供了插件機制來做自定義的轉(zhuǎn)換。
這一節(jié),我們通過一個 px 自動轉(zhuǎn) rem 的功能來入門一下 postcss 的插件。
postcss 的原理
postcss 是 css 到 css 的轉(zhuǎn)譯器,它也和 babel 一樣,分為 parse、transform、generate 3個階段。各種轉(zhuǎn)換插件都是工作在 transform 階段,基于 AST 做分析和轉(zhuǎn)換。
css 的 AST 比 js 的簡單多了,主要有這么幾種:
atrule:以 @ 開頭的規(guī)則,比如:
- @media screen and (min-width: 480px) {
- body {
- background-color: lightgreen;
- }
- }
rule:選擇器開頭的規(guī)則,比如:
- ul li {
- padding: 5px;
- }
decl:具體的樣式,比如:
- padding: 5px;
比起 js parser 的那幾十種 AST 是不是簡單的多?
這些可以通過 astexplorer.net 來可視化的查看:
postcss 插件的寫法
postcss 插件是工作在 transform 階段,處理 ast 節(jié)點,插件的形式是這樣的:
- const plugin = (options = {}) => {
- return {
- postcssPlugin: '插件名字',
- Rule (node) {},
- Declaration (node) {},
- AtRule (node) {}
- }
- }
外層函數(shù)接受 options,返回一個插件的對象,聲明對什么節(jié)點做處理的 listener,然后在對應(yīng)的 listener 里寫處理邏輯就行。
還可以這樣寫:
- module.exports = (opts = {}) => {
- return {
- postcssPlugin: '插件名字',
- prepare (result) {
- // 這里可以放一些公共的邏輯
- return {
- Declaration (node) {},
- Rule (node) {},
- AtRule (node) {}
- }
- }
- }
- }
在 prepare 里返回各種 listener,這樣比起第一種來,好處是可以存放一些公共的邏輯。
然后可以這樣來運行插件:
- const postcss = require('postcss');
- postcss([plugin({
- // options
- })]).process('a { font-size: 20px; }').then(result => {
- console.log(result.css);
- })
下面我們來寫一個簡易的 px 自動轉(zhuǎn) rem 的插件來練練手。
實戰(zhàn)案例
需求描述
px 是一個固定的長度單位,而設(shè)備視口的尺寸是各種各樣的,我們想通過一套樣式來適配各種設(shè)備的顯示,就需要相對的單位,常用的是 rem。
rem 的本質(zhì)就是等比縮放,相對于 html 元素的 font-size。
比如 html 的 font-size 設(shè)置為 100px,那 1rem 就等于 100px,之后的樣式如果是 200px 就寫為 2rem。
這樣我們只需要修改 html 的 font-size 就可以適配各種屏幕寬度的顯示,具體的單位會做等比縮放。
我們要根據(jù) html 的 font-size 值來把所有的 px 轉(zhuǎn)換為 rem,一般都是手動來做這件事情的,但比較繁瑣,知道了計算方式之后,完全可以用 postcss 插件來自動做。
接下來我們就實現(xiàn)下這個 postcss 插件
代碼實現(xiàn)
我們搭一下插件的基本結(jié)構(gòu),只需要聲明對 Declaration 處理的 listener:
- const plugin = (options) => {
- return {
- postcssPlugin: 'postcss-simple-px2rem',
- Declaration (decl) {
- }
- }
- }
然后要做的就是把 decl 的樣式值中的 px 轉(zhuǎn)換為 rem,簡單的正則替換就行:
- const plugin = (options) => {
- const pxReg = /(\d+)px/ig;
- return {
- postcssPlugin: 'postcss-simple-px2rem',
- Declaration (decl) {
- decl.value = decl.value.replace(pxReg, (matchStr, num) => {
- return num/options.base + 'rem';
- });
- }
- }
- }
通過字符串的 replace 方法來做替換,第一個參數(shù)是匹配的字符串,后面的參數(shù)是分組,第一個分組就是 px 的值。
計算 px 對應(yīng)的 rem 需要 1rem 對應(yīng)的 px 值,可以支持通過 options 來傳入。
然后我們測試下:
- postcss([plugin({
- base: 100
- })]).process('a { font-size: 20px; }').then(result => {
- console.log(result.css);
- })
可以看到,已經(jīng)正確的做了轉(zhuǎn)換:
當然,我們這個插件只是案例,還不夠完善,要做的完善的話需要更復(fù)雜的正則。
總結(jié)
postcss 是 css 的 transpiler,就像 babel 是 js 的 transpiler 一樣,而且 postcss 的 AST 只有幾種節(jié)點,比較簡單,也可以通過 astexplorer.net 來可視化的查看。
postcss 也提供了插件功能,可以做一些自定義的分析和轉(zhuǎn)換。
我們實現(xiàn)了簡單的 px 自動轉(zhuǎn) rem 的插件:
rem 是通過等比縮放的方式來達到一套樣式適配不同設(shè)備寬度的顯示的方案,需要做 px 到 rem 的轉(zhuǎn)換,這件事可以用 postcss 插件來自動來做。
其實 postcss 插件的分析和轉(zhuǎn)換功能還有很多的應(yīng)用,比如切換主題色,從白到黑,完全就可以用 postcss 自動分析顏色的值,然后做轉(zhuǎn)換。
postcss 分析和轉(zhuǎn)換 css 的能力還是很強大很有用的,有很多在業(yè)務(wù)中的應(yīng)用場景等你去發(fā)掘。