@keyframes 必须定义在顶层且名称为静态字符串,因Less编译器将其视为指令而非普通规则,不支持变量插值;正确做法是顶层定义关键帧,用mixin封装动画调用逻辑。

@keyframes 在 Less 中无法嵌套,也不能在 mixin 内部或选择器里定义——它必须出现在顶层,且名称必须是静态字符串。试图写成 .box { @keyframes slide { ... } } 会直接编译失败或输出无效 CSS。
为什么 @keyframes 名称不能用变量拼接?
Less 编译器把 @keyframes 当作指令而非普通规则块处理,插值语法 @{name} 在 @keyframes 后面不被识别(除非用字符串拼接 hack)。常见错误包括:
- 写
@keyframes @{prefix}-slide却没启用 strict-math 或字符串插值,导致编译报错ParseError: Unexpected token - 依赖
&-slide想继承父类名,但@keyframes不从属选择器,&在这里无效 - 多个文件重复定义同名
@keyframes fade-in,最终 CSS 里出现多份声明,白占体积
用 mixin 封装动画声明 + 应用逻辑,但别在 mixin 里放 @keyframes
正确做法是把关键帧定义留在顶层,用 mixin 控制调用方式和参数。比如:
.animate(@name, @duration, @timing: ease, @delay: 0s, @count: 1, @fill: forwards) {
animation-name: @name;
animation-duration: @duration;
animation-timing-function: @timing;
animation-delay: @delay;
animation-iteration-count: @count;
animation-fill-mode: @fill;
-webkit-animation-name: @name;
-webkit-animation-duration: @duration;
-webkit-animation-timing-function: @timing;
-webkit-animation-delay: @delay;
-webkit-animation-iteration-count: @count;
-webkit-animation-fill-mode: @fill;
}调用时:.btn { .animate(slideIn, 0.4s, cubic-bezier(0.2, 0.8, 0.4, 1)); }
立即学习“前端免费学习笔记(深入)”;
- 必须显式写
animation-fill-mode: forwards,否则动画结束立刻回退 - 单位统一用
s或ms,Less 不自动转换300ms → 0.3s - 简写
animation: slideIn 0.4s容易漏掉fill-mode或iteration-count,浏览器静默忽略整条
需要动态生成多个关键帧?用递归 mixin + 字符串插值
Less 没有 for 循环,靠递归 + when 守卫生成帧序列。例如生成 8 帧 opacity 动画:
.keyframes-opacity(@name, @frames, @i: 1) when (@i =< @frames) {
@p: percentage((@i - 1) / (@frames - 1));
@{p} { opacity: (@i * 0.1); }
.keyframes-opacity(@name, @frames, (@i + 1));
}
<p>@keyframes fade-8-steps {
.keyframes-opacity(fade-8-steps, 8);
}- 帧数必须用
@frames - 1做分母,才能保证首尾分别是0%和100% -
@{p}插值只能用于选择器或属性值,不能放在@keyframes外任意位置 - 每增加 1 帧,就多一条 CSS 规则;10 个动画 × 12 帧 = 120 行 CSS,影响构建速度和 DevTools 行号映射
真正难的不是写出能跑的代码,而是控制产出——@keyframes 的全局性、命名冲突风险、递归膨胀带来的构建负担,这些不会在浏览器里报错,却会在 CI 环境或团队协作中突然暴露。


















