css自定义属性仅存储字符串,不参与计算;calc()负责运行时计算,var()仅作值替换,sass math.*为编译时静态计算,三者时机与能力不同,混用易出错。

CSS 自定义属性本身不参与任何计算,它只是存储一个字符串值;真正做计算的是 calc()、var() 函数调用、或 Sass 编译器——三者运行时机和能力完全不同,混用就会出错。
var() 只是值替换,不是表达式求值
var(--gap) 的作用非常朴素:在 CSS 解析阶段,把该函数替换成对应变量的当前值(字符串),然后继续走后续的属性解析流程。它不会做加减乘除,也不检查单位是否合法。
- 如果
--gap: 16px,那么margin: var(--gap)等价于margin: 16px - 如果
--gap: 16(没单位),那margin: var(--gap)就是无效声明,被浏览器忽略 -
var(--a) + var(--b)是非法语法,CSS 不支持函数外直接拼接运算符 - fallback 值(如
var(--gap, 8px))也必须是合法 CSS 值,不能是表达式
calc() 才是运行时计算的主力
所有涉及动态尺寸的逻辑(比如“容器宽减去左右 padding 和 border”),必须靠 calc() 完成,且它只能接收数字、带单位的量、以及 var() 调用作为子表达式。
-
width: calc(100% - var(--sidebar-width) - 2px)✅ 合法,var()在calc()内部被提前展开 -
width: calc(var(--sidebar-width) * 2)✅ 支持乘除,但要求--sidebar-width是带单位的值(如240px) -
width: calc(var(--col-count) * 1fr)❌ 错误:--col-count是字符串"3","3" * 1fr无法解析 - 正确写法是
grid-template-columns: repeat(calc(var(--col-count) * 1), 1fr)——注意这里repeat()第一个参数必须是整数,所以仍需确保--col-count是纯数字(如 JS 设置时用el.style.setProperty('--col-count', 3))
Sass math.* 是编译时静态计算,和 CSS 变量无关
很多人想用 math.div(100%, $cols) 来生成栅格宽度,这完全可行,但它和 var(--col-count) 没半点关系——Sass 在构建时就把结果算死了,输出的是像 width: 33.333333% 这样的固定值。
-
math.div(100%, 3)→ 输出33.333333%,无运行时响应能力 -
math.div(100px, 3)→ 输出33.333333px,单位必须显式携带,不能混用px和rem -
width: (100% / 3)在旧 Sass 中可能不触发除法,必须写成width: math.div(100%, 3)或加括号width: (100% / 3) - 别在
@for循环里反复调用math.pow($base, $i),提取为变量复用,避免编译膨胀
order、grid-template-* 等属性对变量类型极其敏感
这些属性表面接受数字,实际只认「可解析为数字的字符串」。直接 order: var(--order) 多数浏览器会当无效值处理,回退到 0。
- 稳妥写法是
order: calc(var(--order) * 1)或order: calc(var(--order) + 0),强制类型转换 -
grid-template-columns: calc(var(--col-width) * 1) 1fr❌ 错误:calc 不能嵌套在grid-template-columns的非函数上下文中 - 正确方式是把整个模板字符串交给 JS 动态设置:
el.style.gridTemplateColumns = `${colWidth}px 1fr`,或用attr()(不推荐,兼容性差) - 媒体查询中重设变量值(如
@media (min-width: 768px) { :root { --col-count: 4; } })才能让calc()基于新值重算
最常被忽略的一点:CSS 自定义属性的“动态”仅限于值变更后触发布局重排,它本身没有计算引擎。所有数学逻辑要么推给编译时(Sass),要么交给运行时(calc() + JS 控制变量),二者边界一旦模糊,就会出现“写了却没变”“控制台没报错但样式不对”的静默失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











