CSS变量不能在@keyframes中直接使用var(),必须通过calc(var(--x))间接引用或在animation属性中绑定;内联style设置变量最灵活,@import引入关键帧需谨慎。

在 @keyframes 里直接写 var(--x) 是无效的
这不是浏览器 bug,而是 CSS 动画规范明确禁止的行为:@keyframes 块内部不解析 CSS 变量,所有 var(--foo) 声明都会被忽略,变成无效样式。你看到动画没反应、属性没生效,大概率是栽在这里。
真正起作用的路径只有一条:变量必须定义在「触发动画的元素」上(比如 .card 或 :root),然后通过 animation 属性本身或其子属性(如 animation-duration、animation-timing-function)绑定变量;或者,在动画属性值中用 calc() 或函数式写法间接引用——但不能出现在 @keyframes 体内。
-
@keyframes slide { 0% { transform: translateX(0); } 100% { transform: translateX(var(--dist)); } }→ ❌ 白写,浏览器静默丢弃 -
.item { --dist: 200px; animation: slide 0.4s ease; }+@keyframes slide { 0% { transform: translateX(0); } 100% { transform: translateX(calc(var(--dist))); } }→ ✅ 有效(注意calc()包裹) -
.item { animation-duration: var(--dur, 0.3s); }→ ✅ 直接生效,无需@keyframes配合
calc() 是让变量进关键帧的唯一合法入口
想让位移、缩放、透明度等数值随变量变化,必须把 var() 塞进 calc() 里,且只能用于支持计算的属性(transform、top、width 等),不能用于 animation-name 或 opacity 这类非计算型属性。
示例场景:网格项逐个右移,每项终点不同
立即学习“前端免费学习笔记(深入)”;
- 定义变量:
.grid-item:nth-child(1) { --offset: 100px; }、.grid-item:nth-child(2) { --offset: 180px; } - 复用动画:
@keyframes slideIn { 0% { transform: translateX(-20px); } 100% { transform: translateX(calc(var(--offset))); } } - 触发动画:
.grid-item { animation: slideIn 0.5s cubic-bezier(0.2, 0.8, 0.3, 1); }
注意:calc(var(--offset)) 中的括号不能省,Safari 15.4 之前甚至不支持 cubic-bezier(var(--x1), ...) 这种函数内嵌变量写法,务必测试目标环境。
用内联 style 注入变量最灵活
当变量值来自 JS 计算、用户交互或服务端数据时,硬写 :nth-child 或 :root 不现实。直接在 HTML 元素上用 style="--offset: 120px" 设置,是最轻量、最可控的方式。
- HTML:
<div class="anim" style="--offset: 150px; --delay: 0.2s"></div> - CSS:
.anim { animation: slideIn var(--delay, 0.3s) ease-out; }+ 关键帧里用calc(var(--offset)) - JS 动态改:
el.style.setProperty('--offset', '220px'),动画会立刻响应(前提是已应用animation)
这种方式绕过所有选择器限制,也避免全局污染,适合组件化场景。但要注意:内联样式优先级高于外部 CSS,别让 !important 和它打架。
动画库拆分时,@import 不等于 <link>
把一堆 @keyframes 抽成单独文件后,用 @import "animations.css" 在主样式表里引入,看起来干净,但实际可能失效——@import 是 CSS 层面的同步阻塞加载,且部分构建工具(如旧版 Webpack css-loader)默认不展开它,导致 @keyframes 根本没注册进样式表。
- ✅ 推荐:
<link rel="stylesheet" href="animations.css">,确保并行加载、缓存复用、运行时可用 - ✅ 构建时内联:用 Sass/PostCSS 的
@import或postcss-import插件,在编译阶段把内容插入主 CSS - ⚠️ 慎用 JS 注入:
document.styleSheets[0].insertRule("@keyframes bounce {...}"),适合按需加载,但要注意注入时机(DOM ready 后)和重复注入风险
复杂动画往往依赖多个变量组合(持续时间、贝塞尔曲线、偏移量),最容易被忽略的是:这些变量一旦设在 :root,就全局生效,不同组件间容易冲突。局部变量 + 内联 style,才是可维护的底线。


















