@keyframes里不能直接用var(),因为css变量是运行时解析的,而关键帧要求声明静态可计算以支持插值;直接使用如transform: translatex(var(--offset))会被忽略,属性取初始值或fallback。

为什么@keyframes里不能直接用var()?
因为 CSS 变量在 @keyframes 内部不会被解析为可插值的值——浏览器规范明确要求,@keyframes 中的声明必须是静态可计算的,而 var(--x) 是运行时才确定的,无法参与关键帧间的插值计算。你写 transform: translateX(var(--offset)); 在 @keyframes 里,它会被当成无效声明忽略,动画仍会执行,但该属性始终取初始值或 fallback(比如 translateX(0)),而不是你预期的变量值。
变量“穿透”关键帧的唯一可行路径
真正能动态控制动画行为的方式,是把变量定义在**触发动画的元素上**,再通过 calc() 或函数式语法,在「元素的动画属性」中引用,而非写进 @keyframes 主体:
-
animation-duration: var(--dur, 0.4s);✅ 安全,浏览器支持变量绑定到动画单项属性 -
animation-timing-function: cubic-bezier(var(--x1, 0.25), var(--y1, 0.1), ...);✅ Safari 15.4+ 支持,旧版 Safari 会退化为ease -
@keyframes slide { to { transform: translateX(calc(var(--tx, 0) * 1px)); } }✅ 关键帧内用calc(var())是兜底方案,但注意:它依赖元素自身样式中的--tx值,且每次 JS 改--tx都会触发动画重绘(不是重放)
性能陷阱:calc(var()) + 大量元素 = 样式计算飙升
当 calc(var(--base) * 2) 出现在 1000 个元素的关键帧驱动属性中,浏览器无法静态折叠,必须为每个元素保留运行时计算逻辑。实测显示,这类写法比预设好值(如 --base-wide: 32px;)多出 12–18ms 的 Recalculate Style 时间。更糟的是,如果变量定义在 :root,一次 document.documentElement.style.setProperty('--base', '16px') 会强制所有用到它的选择器全量重算,不管是否正在动画。
容易被忽略的一点:getComputedStyle(el).transform 这类读取操作,只要结果依赖 var() 和 calc(),就会触发同步布局——在滚动或拖拽循环中调用,卡顿立刻出现。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











