写了八年样式,每次想给 CSS 加个带参数的逻辑都要靠预处理器——今天浏览器终于有自己的函数了
以前想给 CSS 加个带参数的逻辑,只能靠 Sass 预处理器。写一个 px 转 rem 的函数,要在构建时跑一遍 Sass,输出完就是一堆硬算好的 rem 值,下次改设计稿还要重新 build。这个流程前端工程师忍了十几年。
现在不一样了。Chrome 139(2025 年 6 月)和 Firefox 139、Safari 26 同一天把 @function 送进了稳定版,浏览器成了 CSS 的原生运行时。
基本用法是这样的:
@function --px-to-rem(--px type(length)) {
result: calc(var(--px) / 16 * 1rem);
}
h1 {
font-size: --px-to-rem(32px); /* 2rem */
}
p {
font-size: --px-to-rem(16px); /* 1rem */
}
定义一个函数,用 -- 开头(这是 CSS 自定义函数的规范写法),声明参数和类型,在函数体里用 result: 声明返回值。调用的时候直接 --px-to-rem(32px),不用 build,不用变量桥接,浏览器实时算出来。
Sass 函数是编译时的。CSS @function 是运行时的。这是两个完全不同的东西。
Sass 函数在构建阶段执行,输出的是纯 CSS——编译完成之后函数调用就已经变成了硬算出来的值,函数签名里传进去的参数全部消失。CSS @function 在浏览器里实时计算,每次渲染都重新算,可以访问 CSS 变量,可以根据媒体查询返回不同值。
举一个 Sass 完全做不到的场景:根据一个 CSS 变量动态返回颜色。
@function --theme-color(--variant type(string)) {
result: if(
var(--variant) == "primary",
var(--color-primary),
if(
var(--variant) == "danger",
var(--color-danger),
var(--color-default)
)
);
}
.button {
background-color: --theme-color("primary");
}
这里的 if() 是 CSS 原生函数,不是 Sass 的。三元逻辑直接写在 CSS 里,配合 CSS 变量可以在不改 JavaScript 的情况下通过 attribute 修改整个按钮的主题。
再比如流体排版。
@function --fluid-type(--min type(length), --max type(length)) {
result: clamp(var(--min), calc(var(--min) + (var(--max) - var(--min)) * 5vw), var(--max));
}
h1 {
font-size: --fluid-type(18px, 48px);
}
这个函数封装了完整的 clamp 逻辑,传一个最小值和最大值,自动把 5vw 的缩放因子算进去。所有标题复用这一个函数,改设计稿只改两行参数,不用在每个组件里重新写 clamp。
Chrome 139、Edge 139、Firefox 139、Safari 26 全部稳定。这是一个浏览器在 2025 年 6 月就基本覆盖完毕的特性,但在国内的前端社区里,知道的人还很少。
为什么这件事值得专门说?因为它代表 CSS 的角色变了。CSS 以前是纯声明式的——你告诉它是什么,它就输出什么,没有逻辑,没有函数,没有条件。Sass 是这个局限的补丁,把逻辑塞进了构建流程里。但构建时算好就意味着脱离了运行时,脱离了用户交互,脱离了 CSS 变量可以随时改变的那个上下文。
@function 把这个关系彻底翻了。浏览器成了 CSS 的运行时,设计系统里的 spacing、颜色、字体大小这些逻辑可以全部收敛到 CSS 里,不用 build,不用 JS 桥接,不用在每个框架里重复写同样的计算函数。
下一步:打开 Chrome 139(或者任何主流浏览器),在 DevTools 里试一行 --spacing(n),看看控制台有没有报 unknown function。如果支持,你就已经在 CSS 运行时里了。
评论区
登录后可评论。