一開始我們在「點石成金的秘術」中,直接寫正規表示式去解析 css 屬性值,以獲取函式呼叫字串,並用函式執行後的結果替換該字串。
後來覺得正規太難了,所以我們在「煉金術的精密儀器」利用 postcss-value-parser
將 css 屬性值解析成 AST 來操作,雖然不再擔心自己正規寫不好,但函式執行並替換這件事情還是有些瑣碎。
而這篇將分享我現在工作時所使用的工具:postcss-functions
,他將我們原本做的事情全部完成:
也就是說,我們只需傳給他聲明的計算函式即可~他有一個 option
參數,裡面就只有一個 functions
選項可以寫。
跟「點石成金的秘術」相同的模擬情境!
package.json
{
"type": "module",
"devDependencies": {
"postcss-functions": "^4.0.2",
"postcss-load-config": "^6.0.1",
"vite": "^7.1.4"
}
}
index.html
<link rel="stylesheet" href="./normal.css">
normal.css
p {
width: calc(add(multiply(3, 3), 2)px + 3px);
padding: calc(multiply(add(multiply(1, 2), multiply(3, 4)), 5)px + 3px) multiply(3, 3)px;
}
postcss.config.js
import postcssFunctions from 'postcss-functions'
/** @type {import('postcss-load-config').Config} */
export default {
plugins: [
postcssFunctions({
functions: {
add: (a, b) => parseFloat(a) + parseFloat(b),
multiply: (a, b) => parseFloat(a) * parseFloat(b),
},
}),
],
}
只需將聲明的計算函式傳入 functions
中,postcss-functions
就會幫我們完成之前做的所有事情了~
結果
% npx vite build --minify false
dist/assets/index-CkZrhj5N.css 0.07 kB │ gzip: 0.07 kB
% cat ./dist/assets/index-CkZrhj5N.css
p {
width: calc(11px + 3px);
padding: calc(70px + 3px) 9px;
}
編譯結果與預期的一致,是不是很簡單啊~
還記得我們最初學 postcss
的目標嗎?當時希望將三大公式用函式呼叫替代:
calc(設計稿上的值 / 設計稿寬度 * 100vw)
。pxToVw(設計稿上的值, 設計稿寬度)
。min(設計稿上的值px, calc(設計稿上的值 / 設計稿寬度 * 100vw))
。max(設計稿上的值px, calc(設計稿上的值 / 設計稿寬度 * 100vw))
。pxToVwClamp(設計稿上的值, 設計稿寬度)
。calc((100vw - 設計稿寬度) / 2 + (設計稿上的值))
。pxToVwExtend(設計稿上的值, 設計稿寬度)
。此刻,我們只需將函式給實現,並傳給 postcss-functions
即可,開始吧!
index.html
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./normal.css">
<div class="pxToVw">pxToVw</div>
<div class="pxToVwMin">pxToVwMin</div>
<div class="pxToVwMax">pxToVwMax</div>
<div class="pxToVwExtend">pxToVwExtend</div>
normal.css
* {
margin: 0;
padding: 0;
}
.pxToVw {
margin-left: pxToVw(50, 375);
}
.pxToVwMin {
margin-left: pxToVwClamp(50, 375);
}
.pxToVwMax {
margin-left: pxToVwClamp(-50, 375);
}
.pxToVwExtend {
margin-left: pxToVwExtend(50, 375);
}
所有等比縮放公式都改用函式呼叫。
postcss.config.js
import postcssFunctions from 'postcss-functions'
// [等比縮放]
// . calc(設計稿上的值 / 設計稿寬度 * 100vw)
const pxToVw = (value, designDraft) => {
value = parseFloat(value)
designDraft = parseFloat(designDraft)
return `${value / designDraft * 100}vw`
}
// [有限的等比縮放]
// . value > 0: min(設計稿上的值px, calc(設計稿上的值 / 設計稿寬度 * 100vw))
// . value < 0: max(設計稿上的值px, calc(設計稿上的值 / 設計稿寬度 * 100vw))
// . value = 0: 0
const pxToVwClamp = (value, designDraft) => {
value = parseFloat(value)
designDraft = parseFloat(designDraft)
if (value === 0) {
return 0
}
return value > 0 ? `min(${value}px, ${pxToVw(value, designDraft)})` : `max(${value}px, ${pxToVw(value, designDraft)})`
}
// [延伸固定]
// . calc((100vw - 設計稿寬度) / 2 + (設計稿上的值))
const pxToVwExtend = (value, designDraft) => {
value = parseFloat(value)
designDraft = parseFloat(designDraft)
return `calc((100vw - ${designDraft}px) / 2 + (${value}px))`
}
/** @type {import('postcss-load-config').Config} */
export default {
plugins: [
postcssFunctions({
functions: {
pxToVw,
pxToVwClamp,
pxToVwExtend,
},
}),
],
}
不論哪個公式所對應的計算函式,都應該接收兩個參數:設計稿上的值與設計稿寬度,將傳入的參數套進公式中返回就搞定了!
結果
% npx vite build --minify false
dist/assets/index-DZlluprw.css 0.28 kB │ gzip: 0.15 kB
% cat ./dist/assets/index-DZlluprw.css
* {
margin: 0;
padding: 0;
}
.pxToVw {
margin-left: 13.333333333333334vw;
}
.pxToVwMin {
margin-left: min(50px, 13.333333333333334vw);
}
.pxToVwMax {
margin-left: max(-50px, -13.333333333333334vw);
}
.pxToVwExtend {
margin-left: calc((100vw - 375px) / 2 + (50px));
}
% npx vite preview
當視窗小於 375 時:
pxToVw
、pxToVwMin
、pxToVwMax
距離視窗左邊是維持相同比例的縮放。pxToVwExtend
永遠釘在原地。當視窗大於 375 時:
pxToVw
距離視窗左邊越來越遠。pxToVwMin
、pxToVwMax
距離視窗左邊的尺寸是一樣的(數值停止增減)。pxToVwExtend
還是釘在原地。以上就是 postcss-functions
具體使用方法~將我們前面所做的事情變得輕鬆愜意 😃
我們從「等比縮放公式由來」,到「函式呼叫替換公式」,這一切的分享在此刻都串起來了!
並且以三個層面分享「函式呼叫替換公式」完整的思路,從正規表示式到AST,到這篇的直接給 functions ,保證了在不依賴 postcss
的開發環境中,你還是能用其他工具成功應用這一套工作流。
下一篇,我們就要來將「實戰3:無痕的延伸固定之術」更新,讓我們遠離超爆長公式吧!