CSS 开始有函数和条件了:@function 与 if()
CSS 新增的 @function 与 if() 把「一个组件多种状态」从媒体查询复制粘贴里解放出来。两者都还没到 Baseline,但值得先看懂它们替代了什么。
CSS 拿到了两个新东西:能定义函数,和能写条件。都还在实验阶段,但它们替代的东西是每个项目里都有的那种重复。
@function:能在运行时读自定义属性的函数
@function --step(--n <number>: 1) returns <length> {
result: calc(var(--space-unit) * var(--n));
}
.card {
padding: --step(2);
}
语法是 @function --名字(--参数 <类型>: 默认值) returns <类型> { ... },返回值写成 result:,调用就写 --名字(实参)。
它和 SCSS 函数的区别不在写法,在求值时机:
| 求值时机 | 能读 var() 吗 |
|
|---|---|---|
| SCSS 函数 | 构建期 | ❌ 看不到运行时值 |
CSS @function |
计算值阶段 | ✅ |
这一条决定了它的价值。凡是「令牌是自定义属性、函数要基于令牌算」的地方,预处理器函数都做不到 —— 它根本不知道 var(--space-unit) 会是什么。这也是我在这一站上把换肤做成令牌体系之后,一直想要的东西。
if():把三份重复的声明收成一份
.card {
grid-template-columns: if(
media(width < 40rem): 1fr;
else: 14rem 1fr;
);
}
它支持三种测试:style()(看自定义属性的值)、media()、supports(),并且可以带 else、可以写多个分支。
style() 那个形态最有用:
.badge {
color: if(
style(--skin: ink): var(--c-accent);
style(--skin: riso): var(--c-ink-2);
else: var(--c-text);
);
}
以前要写这一段,只能把同一个选择器在三个 [data-skin=...] 块里各写一遍。
现状:都还没到 Baseline
MDN 对两者的标注是一样的:Limited availability、非 Baseline、实验性。也就是说最新浏览器能用,但别指望旧设备。
现在能用它们的方式只有渐进增强 —— 而且顺序很关键:
.card {
/* 先写旧写法:不认识 if() 的浏览器用这一条 */
padding: 1rem;
padding: if(media(width > 60rem): 1.5rem; else: 1rem);
}
CSS 解析不了的值会整条声明丢弃,所以旧浏览器会安静地留在上一条。反过来写就没救了。
我的判断
if() 的收益比 @function 大。
条件分支是每个组件都会撞上的重复 —— 断点、皮肤、深浅色,每加一维就多一层复制。而函数抽取只在少数几个地方真的划算,多数 calc() 组合抽出来并没有更好读。
还有一条要克制的:CSS 正在从纯声明式变成「声明式 + 一点点编程」,但它仍然是级联优先的。这些特性不该被拿来搭状态机 —— 一旦你开始用 if() 模拟状态转移,说明这段逻辑本来就不该待在样式里。

评论
…