scss 顶层不能用 @each 遍历生成 @keyframes,因 css 要求关键帧名必须是静态字符串;须封装进 @mixin 再 @include 调用,确保名称静态、可复用、命名可控。

不能在 SCSS 顶层用 @each 直接遍历列表生成 @keyframes,否则编译失败;必须把遍历逻辑封装进 @mixin,再通过 @include 调用,才能生成合法、可复用、命名可控的关键帧规则。
为什么 @each 在顶层遍历 @keyframes 会报错
SCSS 编译器要求 @keyframes 名称必须是静态字符串,不接受变量或插值表达式。即使你写的是 @each $name in (slow, medium, fast) { @keyframes shine-#{$name} { ... } },也会触发类似 Invalid CSS after "@keyframes shine-": expected identifier, was "#{$name}" 的错误。根本原因不是 SCSS 不支持循环,而是 CSS 标准本身禁止运行时解析关键帧名——浏览器需要在解析阶段就能索引到确定的动画名。
正确做法:用 @mixin + @each 封装遍历逻辑
把列表遍历收进 @mixin,调用时展开为独立、静态的 @keyframes 声明。这样既满足 CSS 规范,又保留参数化能力。
- 定义带项目前缀的名称,如
my-skeleton-shine-slow,避免全局冲突 - 列表内容应为明确的键值对(
(slow: 2s, medium: 1.5s, fast: 1s)),方便在关键帧内直接使用$duration - 关键帧内部所有数值必须展开为静态值,不要用
calc()或 CSS 变量,否则动画节奏不可控 - 每个关键帧只声明一次,不重复生成;
@mixin调用位置应统一放在_animations.scss等入口文件中
示例:
@mixin generate-skeleton-shine($speeds: (slow: 2s, medium: 1.5s, fast: 1s)) {
@each $name, $duration in $speeds {
@keyframes my-skeleton-shine-#{$name} {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
}
}
@include generate-skeleton-shine;
常见踩坑点:名称拼接、作用域与降级 fallback
很多人试图在 @each 中拼接更多动态信息,比如 @keyframes my-shine-#{$name}-#{$direction},这看似灵活,实则危险:
- 名称越长、变量越多,越容易在团队协作中产生命名冲突,CI 工具
grep无法可靠识别 -
@keyframes是 CSS 全局作用域,@use或@forward无法隔离它,拼接名等于放弃可维护性 - IE11 不支持
@keyframes,但循环生成不会自动补opacity或visibilityfallback,必须手动加 - 若需不同方向的扫光动画(左→右 / 上→下),应定义独立语义化名称(
my-skeleton-shine-x/my-skeleton-shine-y),而不是靠变量拼接
真正需要“多维参数”的场景,应该拆成多个专用 @mixin,而非在一个循环里塞进所有变量。名称静态、行为清晰、调用简单,才是 SCSS 动画批量生成的底线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











