@keyframes名称必须为静态字符串,因css标准要求浏览器可索引且sass顶层不支持变量插值;正确做法是用@mixin封装@for循环生成带项目前缀的静态关键帧名,如my-skeleton-shine-slow。

为什么不能在顶层用 @for 生成 @keyframes
直接写 @for $i from 1 through 3 { @keyframes slide-#{$i} { ... } } 会编译失败,报错类似 Invalid CSS after "@keyframes slide": expected identifier, was "#{$i}"。CSS 标准要求关键帧名必须是静态字符串,Sass 不允许在顶层作用域做变量插值——它只认字面量名称。
这不是 Sass 的限制太死,而是浏览器解析动画时依赖确定的、可索引的 @keyframes 名;运行时拼接名等于把动画定义变成不可靠的“伪动态”,CI 工具 grep 出来的全是隐患。
- 唯一合法路径:把循环逻辑收进
@mixin,调用时展开 - 每个
@keyframes必须有唯一、带项目前缀的静态名(如my-skeleton-shine-slow) - IE11 等旧环境不支持
@keyframes,批量生成后还得手动补opacityfallback,不能指望循环自动处理
怎么用 @mixin + @for 安全批量生成关键帧
封装一个生成 mixin,每次调用产出一组独立、命名可控的关键帧:
@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;
}
}
}
}
然后在 _animations.scss 里调用一次:@include generate-skeleton-shine;。生成结果是三个静态关键帧:my-skeleton-shine-slow、my-skeleton-shine-medium、my-skeleton-shine-fast,无冲突、可 grep、可单独引用。
- 别在
@content里再嵌套循环——@keyframes内部不允许@for - 所有数值必须展开为静态值,不要用
calc()或 CSS 变量,否则动画节奏不可控 - 生成体积可控:10 个档位增加约 1KB CSS,远小于 JS 注入或 runtime style 操作
如何让批量生成的关键帧被安全调用
关键帧名是 CSS 全局作用域,哪怕你用了 @use,编译后 @keyframes my-fade-in 仍是全局的。所以调用层必须和定义层解耦:
- 每个关键帧配一个同名
@mixin(如@mixin skeleton-shine-slow),只控制animation属性值,不碰关键帧内容 -
@mixin参数仅限行为控制:$duration、$easing、$fill,绝不传整条animation字符串 - 入口文件用
@use 'animations' with ($prefix: 'my-')透传前缀,确保未来能批量切换命名空间 -
_animations.scss必须显式@forward 'core'或@export,否则@use后访问不到内部@mixin
最容易被忽略的性能陷阱
批量生成关键帧时,最常被跳过的其实是属性选择。哪怕名字对了、调用对了,只要关键帧里写了 left、top、width 这类触发布局的属性,GPU 就无法加速,动画一卡一卡。
- 只用
transform和opacity:这两类属性走合成层,不触发重排重绘 - 骨架屏扫光动画别用
background-position—— 它虽不重排,但某些安卓 WebView 下渲染不稳定;改用transform: translateX()+mask更稳妥 - 所有数值抽成 SCSS 变量驱动(如
$skeleton-shine-range: 200%),后续统一调整不用改关键帧内部
真正难的不是写循环,而是守住那条线:关键帧名静态、语义化、带前缀;关键帧内容只含 GPU 友好属性;调用层参数化、无副作用、不侵入定义。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











