calc()是css中唯一支持单位运算的函数,变量必须存纯数字才能参与换算,乘除右侧须为无单位数,加减可混单位但%与px相加常被拒,0需显式写为0px/0rem,var(--x)*1px可将无单位数转为像素值,但兼容性要求1px在右,根字号变化时需同步更新基准变量。

calc() 是唯一能用的单位转换入口
CSS变量本身不支持任何运算,--size: 16px * 2这种写法直接被浏览器忽略。真正起作用的只有calc()——它在运行时解析var(--x)并执行加减乘除,但前提是变量值必须是合法长度(如16、16px、1rem),且运算符两侧单位规则明确。
常见错误现象:--gap: calc(var(--base) * 1px)看似合理,但如果--base定义为16px,实际展开是calc(16px * 1px),浏览器报Invalid property value;若--base是16(无单位),则calc(16 * 1px)才合法。
-
calc()内乘除右侧必须是无单位数字:calc(var(--val) * 2)✅,calc(var(--val) * 2px)❌ - 加减运算允许混合单位(如
10px + 2em),但%和px相加多数浏览器拒绝 - 所有变量必须先被
var()引用进calc()内部,不能在变量定义时“预计算”
CSS变量该存带单位还是纯数字?
取决于你后续怎么用。如果目标是响应式换算(比如转rem),变量必须存纯数字;如果目标是直接拼接像素值,存px更直白,但牺牲灵活性。
例如:想让--space-m代表“16像素”,又希望它能参与rem换算,就得定义--space-m: 16(不是16px),再配合calc(var(--space-m) / var(--base-font-size) * 1rem)。这里--base-font-size也必须是纯数字(如16),否则除法失效。
- 存纯数字:适合需要缩放、换算的场景,但每次使用都得补单位(如
* 1px或/ 16 * 1rem) - 存带单位值:适合固定输出,如
--border: 1px solid #000,但无法再做乘除 -
0必须显式写成0px或0rem——单独一个0在calc()里会被当作无量纲数,可能引发类型推断错误
为什么var(--x) * 1px能“复活”无单位变量
因为var(--x)返回的是原始字符串值。--x: 24展开后就是"24",纯数字、无单位、无量纲。CSS不允许24 + 10px,但允许24 * 1px——乘法会把无单位数字“升格”为对应单位的长度值,结果是24px。
这个技巧本质是类型转换,不是魔法。但它有兼容性陷阱:1px * var(--x)在旧版 Safari(15.4 之前)会静默失败,所以务必把带单位的值放在左侧:1px * var(--x)❌,var(--x) * 1px✅。
- 想得到像素值,用
1px最稳妥,不依赖根字体 - 想保持响应式能力,用
1rem,但需确保--base-font-size是纯数字且与实际根字号一致 - 避免用
1em或100%升格——前者随父元素变化,后者语义模糊,容易引发意外缩放
根字号动态变化时,这套逻辑就失效了
calc()在声明时求值,不是运行时监听。如果项目用 JS 动态设置document.documentElement.style.fontSize = '18.75px',而你的--base-font-size: 16没同步更新,所有rem换算都会偏大。
这不是calc()的问题,而是设计假设和实际环境脱节。此时要么构建时注入真实基准值,要么放弃rem改用clamp()或vw方案,比如font-size: clamp(14px, 2.5vw, 18px)。
最容易被忽略的一点:你写的calc(var(--space-m) / 16 * 1rem)看起来很完美,但只要根字号不是16px,它就只是数学正确,视觉错误。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











