CSS变量不能在@keyframes中直接使用,因规范禁止运行时求值;必须将变量定义在动画元素上,并在关键帧中用calc(var(--x))引用,且需设默认值、避免单位混用。

纯 CSS 无法让 @keyframes 内部直接响应 CSS 变量变化——浏览器会忽略 opacity: var(--fade) 这类写法,不是 bug,是规范行为。
为什么 @keyframes 里不能用 var()?
CSS 变量在解析阶段不参与关键帧插值计算,@keyframes 是静态规则,一旦解析完成就固化为数值。变量只在“应用到元素”时才求值,而关键帧体(0% { ... })不属于该求值上下文。
- Chrome、Firefox、Safari 均不支持在
@keyframes块内使用var() - 写进去也不会报错,但会被当成无效声明静默丢弃
- 哪怕搭配
calc(),如transform: translateX(calc(var(--x) * 1px)),也**必须把--x定义在动画触发元素上**,而非@keyframes内部
正确做法:变量挂载在元素上,关键帧里用 calc() 引用
本质是把关键帧“参数化”,靠元素样式驱动重计算。例如实现可配置的水平位移动画:
@keyframes slide-x {
0% { transform: translateX(calc(var(--tx, 0) * 1px)); }
100% { transform: translateX(calc(var(--tx, 100) * 1px)); }
}
.element {
--tx: 100;
animation: slide-x 0.4s ease-in-out;
}- JS 动态改值:
el.style.setProperty('--tx', '250'),浏览器会触发动画重绘 - 务必给变量设默认值(如
var(--tx, 0)),否则未定义时整个calc()会退为0 - 避免在
calc()中混用单位(如var(--x) + 'px'),字符串拼接 JS 不生效,CSS 也不认
animation 简写中嵌变量风险极高
不要写 animation: slide var(--dur) ease; —— Safari 和旧版 Chrome 对简写中变量解析不一致,--dur 缺失时整条声明可能被丢弃。
立即学习“前端免费学习笔记(深入)”;
- 拆开写更安全:
animation-duration: var(--dur, 0.3s); animation-timing-function: cubic-bezier(var(--e1, 0.25), ...); -
cubic-bezier()内可嵌变量,但 Safari ≤15.4 不支持,需降级 fallback - 所有变量都带默认值,否则
animation-duration: var(--dur)在未设变量时等于0s,动画不播
频繁修改变量引发 layout 卡顿怎么办?
每次改 --tx 若依赖 offsetLeft 或触发重排属性(如 width),滚动/拖拽中极易掉帧。
- 优先用
transform+will-change: transform隔离渲染层 - 避免在
scroll回调中直接改变量,用requestAnimationFrame()节流 - 不要用
document.styleSheets[0].insertRule()动态注入新@keyframes—— IE 不兼容,且每次注入都新建规则,内存不可控 - 真正需要完全动态关键帧(比如每帧坐标都不同),应切换到 Web Animations API 的
KeyframeEffect.setKeyframes(),而非硬刚 CSS 变量
关键帧本身是静态的,所谓“动态”只是靠元素样式层触发重计算;变量没生效,第一反应不是检查 JS,而是确认它是否真的挂载到了动画目标元素上,且没被更高优先级样式覆盖。


















