写了十年 CSS 四则运算,今天才知道 calc 里的单位相除能约掉——CSS 第一次能算“两个量之间的关系”
写过 CSS 的人都知道一行铁律:加法和减法的单位必须一致,乘法和除法只能跟一个不带单位的数字玩。于是那个最朴素的需求——”我想知道现在视口宽多少个像素””我想让间距跟某个已有尺寸成比例”——在纯 CSS 里一直做不了。今天这条铁律被松开了:calc(100vw / 1px) 现在是一个合法表达式,而且它给出的不是长度,是一个赤裸裸的数字。
结论先放这:CSS 的值类型系统从”同类型才能运算”,进化到了”同类型相除会约掉、得到一个无单位数”。这件事听起来只是数学课本上的一句话,但它把 CSS 从”能算长度”变成了”能算关系”。
以前的坑:CSS 里没有”比例”这个概念
在 Typed Arithmetic 之前,CSS 的数学规则是这样的:
- 加法/减法:必须同数据类型。
calc(250px - 150px)合法,calc(200px + 100ms)直接失效。 - 乘法:只能乘一个无单位数。
calc(10px * 4)= 40px 合法,calc(10px * 4px)非法,因为 CSS 里没有平方像素。 - 除法:只能除以无单位数。
calc(1000px / 2)= 500px 合法,但calc(1000 / 2px)完全说不通。
问题就出在除法上。calc(100vw / 1px) 这种写法,在旧规则里是无效的——因为设计师没打算让你”除出一个数”。可实际上你要的恰恰是这个数:视口现在到底多少像素宽。
结果就是,前端想拿一个”当前尺寸的比例值”去驱动另一条属性时,只能绕道 JS:读 getBoundingClientRect(),算个比值,再写回 CSS 变量。一个纯视觉的响应式需求,硬生生插了一条 JS 管线,还带上了 layout thrashing 的风险。
现在能做什么:让相除把单位约掉
新规则一句话总结:当一个带类型的值除以同类型的值时,单位相互约掉,结果是一个 <number>。
/* 视口宽度换算成无单位数字 */
--vp-px: calc(100vw / 1px);
/* 如果视口 1000px 宽,--vp-px 就是 1000(无单位) */
/* 如果视口 500px 宽,--vp-px 就是 500(无单位) */
注意除数换成别的单位,结果会完全不同——这恰恰是可控的地方:
/* 除以 1em 而不是 1px,得到的是"视口有多少个 em" */
--vp-em: calc(100vw / 1em);
/* 1000px 视口、默认 16px 字号 → 62.5 */
因为结果是个纯数字,它能被塞进任何只接受数字的属性或函数里:
.card {
/* 数字 → 透明度,视口越宽越不透明 */
opacity: calc(var(--vp-px) / 1000 - 0.5);
/* 数字 × 单位 = 长度,把比值变回旋转角度 */
rotate: calc(var(--vp-px) * 0.036deg);
}
也就是说,你可以用 A 属性的值,去驱动 B 属性的值,中间不用经过 JS。CSS 第一次有了”跨类型换算”的表达力。
三个能立刻用上的场景
1. 响应式透明度/尺度,不再堆媒体查询
过去要写三四个断点,现在一条连续函数搞定。视口从 500px 到 1500px,卡片透明度和缩放平滑跟随,没有跳变。
2. 组件内部的等比缩放
假设你有一个圆形进度条,弧长想跟容器宽度成比例。以前靠固定比例硬编码,或者用 JS 读容器尺寸;现在:
.gauge { --size: 240px; }
.gauge .arc {
width: calc(var(--size) / 10);
/* 用容器宽度算出"多少个单位宽度",再做别的换算 */
}
3. 那类”看起来像魔法”的动画
CSS-Tricks 用 Typed Arithmetic 做过一个螺旋排布 36 个元素的 demo:每个元素的角度和间距都由中心距离推导出来,全靠 calc 在类型之间来回换算。换成旧规则,这段逻辑几乎没法用纯 CSS 写出来。
兼容性与落地建议
这件事不是今天才开始的:Chrome 从 140 起支持同类型相除返回无单位值,Safari 18.2 跟上。所以严格说这不是”今天刚有的新特性”,而是”正在成为 baseline 的一条规则”——webkit 那条博客和 MDN 的 Using typed arithmetic 指南是同时更新的,说明各家的实现已经对齐。
落地上我建议这样:
- 先做特性检测,不要裸用。
@supports (width: calc(100px / 1px))里放新逻辑,外面给回退值。 - 优先用在”纯视觉、错了也不崩”的地方——透明度、缩放、装饰性动画。别拿它去算关键布局的高度,那是给自己挖坑。
- 把比值抽成 CSS 变量。
--vp-px: calc(100vw / 1px)抽成全局变量后,整个项目都能复用它当”响应式标尺”,比到处写100vw清楚得多。 - 动画里注意重算成本。比值随视口变化,视口 resize 时相关属性会重算,别把一堆昂贵属性绑在这上面。
一句话收尾:这条规则真正的价值,不是让你少写一个除号,而是让 CSS 第一次能表达”两个量之间的关系”。以前这种关系活在 JS 的变量里,现在它活在样式表里。下一步可以做的:翻翻你项目里那些”用 JS 读尺寸再写回 CSS”的地方,看看哪些能直接换成一条 calc(… / …)。
评论区
登录后可评论。