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() 模拟状态转移,说明这段逻辑本来就不该待在样式里。

← 返回文章列表

评论

…