@keyframes 必须顶层静态声明,不能嵌套在mixin或选择器内;应拆分动画属性为独立mixin;多动画用class组合而非mixin叠加;响应式节奏需在媒体查询中调用mixin。

@keyframes 必须顶层静态声明,不能放进 mixin 里
所有 @keyframes 规则必须写在 Less 文件最外层,不能嵌套在选择器、.animate() mixin 或媒体查询内部——这是 90% 动画不生效或编译报错的根源。Less 把 @keyframes 当作顶层指令(类似 @import),一旦嵌套,轻则输出空规则,重则直接抛 ParseError: Unexpected token。
常见错误写法:.spin(@speed) { @keyframes spin-@{speed} { to { transform: rotate(360deg); } } }
✅ 正确做法:统一放在 animations/_keyframes.less 中,用固定名称,如:@keyframes spin-fast { to { transform: rotate(360deg); } }@keyframes pulse-border { 0% { border-color: #ccc; } 100% { border-color: #007bff; } }
⚠️ 注意:
• IE11 不识别 from/to,必须写 0%/100%
• 多文件共用时,用 @import (once) "animations/_keyframes.less"; 避免重复输出
拆分 mixin 控制维度,别堆参数
把 animation-name、duration、fill-mode 全塞进一个 .animate(@name, @dur, @easing, @count) 里,极易传错顺序、漏参数、改起来牵一发而动全身。
立即学习“前端免费学习笔记(深入)”;
推荐拆成语义清晰、可叠加的独立 mixin:
• .animate-name(@name) —— 只设 animation-name
• .animate-time(@dur: 0.3s) —— 自动补单位,避免混用 300ms 和 0.3s
• .animate-fill(@mode: forwards) —— 必须显式声明,否则动画一结束就回退到初始态
• .animate-easing(@ease: ease-out) —— 分离缓动函数,方便覆盖
调用示例:.btn { .animate-name(spin-fast); .animate-time(0.4s); .animate-fill(forwards); .animate-easing(cubic-bezier(0.2, 0.8, 0.4, 1)); }
多动画叠加靠 class 组合,不是 mixin 嵌套
想让一个元素同时旋转 + 发光 + 边框脉动,别写 .rotate().glow().pulse()——mixin 是纯文本替换,后声明的 animation 会覆盖前一个,最终只剩最后一条。
可行方式:
• 每个动画对应一个语义 class:.is-spinning、.has-glow、.border-pulsing
• CSS 中用组合选择器定义,HTML 中多 class 控制:<button class="btn is-spinning has-glow">
• 若必须单行启用,提前在顶层定义好组合关键帧,如 @keyframes spin-and-glow,再由单一 mixin 调用
⚠️ 注意:
• 多动画逗号写法(animation: spin 0.4s, glow 1s;)在旧版 Safari 支持不稳定
• 生产环境更推荐 JS 动态增删 class,可控性更强
响应式节奏只靠媒体查询包裹调用
别在 mixin 内部写条件逻辑,比如 .animate() when (@screen = mobile) { animation-duration: 0.2s; }——Less 变量在编译期已确定,无法根据运行时视口动态切换。
正确做法:
• 在媒体查询内调用 mixin:@media (max-width: 768px) { .btn { .animate-time(0.2s); } }
• 或封装带断点的 wrapper:.animate-time-mobile(@dur: 0.2s) { @media (max-width: 768px) { .animate-time(@dur); } }
真正难的不是写出效果,而是让后续维护的人不查文档就能改对——所以参数命名要直白,单位要统一,forwards 要显式写,@keyframes 名称绝不能动态拼接。


















