写了十年 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 指南是同时更新的,说明各家的实现已经对齐。

落地上我建议这样:

  1. 先做特性检测,不要裸用。@supports (width: calc(100px / 1px)) 里放新逻辑,外面给回退值。
  2. 优先用在”纯视觉、错了也不崩”的地方——透明度、缩放、装饰性动画。别拿它去算关键布局的高度,那是给自己挖坑。
  3. 把比值抽成 CSS 变量。--vp-px: calc(100vw / 1px) 抽成全局变量后,整个项目都能复用它当”响应式标尺”,比到处写 100vw 清楚得多。
  4. 动画里注意重算成本。比值随视口变化,视口 resize 时相关属性会重算,别把一堆昂贵属性绑在这上面。

一句话收尾:这条规则真正的价值,不是让你少写一个除号,而是让 CSS 第一次能表达”两个量之间的关系”。以前这种关系活在 JS 的变量里,现在它活在样式表里。下一步可以做的:翻翻你项目里那些”用 JS 读尺寸再写回 CSS”的地方,看看哪些能直接换成一条 calc(… / …)。

评论区

0 条评论

登录后可评论。

铁锈·Rust工具链 946 阅读