必须用 :root 定义动画变量,因其是规范根伪类,确保所有后代(含 svg、iframe)继承;body 或 html 定义会导致 @keyframes 和外部 css 读不到变量,旧版 safari 可能静默回退。

直接在 :root 里定义带单位的 --animation-duration 和 --animation-easing,所有动画声明统一用 var(--animation-duration) 引用,别塞进 @keyframes 里——那里不认变量。
为什么必须用 :root 而不是 html 或 body
只有 :root 是规范定义的文档根伪类,能确保变量被所有后代元素(包括 svg、iframe 内样式)继承。写成 body { --duration: 0.3s; } 看似生效,但 head 里的 @keyframes 或外部 @import 的 CSS 文件根本读不到;旧版 Safari 还可能因继承链断裂导致 var() 静默回退到默认值。
正确写法:
:root {
--animation-duration: 0.3s;
--animation-easing: cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes 里不能用 var()?那怎么动态控制位移或颜色
@keyframes 块内禁止直接使用 var(--offset) 控制关键帧数值(如 transform: translateX(var(--offset))),主流浏览器会忽略整段规则。这不是兼容性问题,是 CSS 动画规范本身限制——关键帧偏移和属性值必须是字面量(0%、from、50px、#fff)。
- 真正可动画的属性(
transform、opacity、color)可以安全引用变量,但前提是变量已定义且作用域可达:transform: translateX(var(--tx, 100px)); - 想让不同元素有不同位移?别改
@keyframes,改调用侧:.card-a { --tx: 200px; } .card-b { --tx: -150px; } - 需要 JS 动态驱动?用内联
style="--tx: 300px"注入最可控,比 class 切换更灵活
如何避免 animation 复合属性被意外覆盖
很多人写 animation: slide var(--duration) var(--easing); 没问题,但一加 animation-fill-mode: forwards; 就失效——因为后续声明没显式包含它,复合属性被重写覆盖了。
- 要么全写进复合声明:
animation: slide var(--duration) var(--easing) forwards; - 要么拆开写单个属性:
animation-name: slide; animation-duration: var(--duration); animation-timing-function: var(--easing); animation-fill-mode: forwards; - 千万别混用:
animation: slide 0.3s; animation-duration: var(--duration);—— 后者会被前者压制 -
transition同理:单独定义--transition-duration,别和--animation-duration共用一个变量,悬停反馈和页面加载动画节奏必须解耦
JS 修改变量后动画没反应?检查这三个点
CSS 变量更新是实时的,但动画不会自动重播。常见卡点:
- 变量名拼错或大小写不符:
--Duration≠--duration,浏览器静默失败 - 没提供
fallback:animation-duration: var(--duration);中若--duration未定义,整条声明被丢弃,动画退回浏览器默认时长(通常是 0s) - 修改后未触发重绘:给元素加个无意义的 class 切换(如
el.classList.toggle('force-repaint')),或临时设el.style.animation = 'none'再恢复,强制浏览器重算动画流
真正容易被忽略的是:变量值带单位必须完整(--duration: 0.3s),不能拆成 --dur-num: 0.3 + --dur-unit: s,CSS 不支持运行时拼接。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











