SCSS递归生成阶梯延迟动画需将递归转化为迭代,用@for生成延迟映射表,再用@each配合nth-child输出CSS规则。nth-child比nth-of-type更可靠,因严格按照DOM顺序计数。移动端iOSSafari在步数超过12时可能卡顿,建议控制步数并使用透明度与变换属性组合。
SCSS递归函数生成阶梯式延迟CSS加载动画
时间:2026-07-27
浏览:186
文章目录
SCSS生成阶梯延迟动画的正确方法
在实际项目中,用SCSS去模拟递归其实是个伪命题。SCSS没有真正的运行时栈,它的“递归”本质上是通过迭代展开的循环。如果强行写一个@return my-function($n - 1)这样的逻辑,编译时必定会报Stack overflow: maximum nesting level reached——这跟语言本身的限制有关,不是代码写得不够“聪明”。
正确做法其实很简单:把递归逻辑转成迭代逻辑,用@for从1到$steps逐层生成一个延迟map就好。这个map只作为数据准备阶段,不输出任何CSS。
@function generate-delays($steps, $base: 0.1s, $increment: 0.1s) {
$result: ();
@for $i from 1 through $steps {
$delay: $base + ($i - 1) * $increment;
$result: map-merge($result, (nth: $i, delay: $delay));
}
@return $result;
}
拿到这个map之后,下一步才是真正的CSS输出环节。这里最容易踩的坑是:试图在@for里直接拼选择器字符串,结果生成了无效的CSS规则(比如.item:nth-child(1)没有被解析为真正的选择器)。正确的做法是用@each配合nth-child()来展开。
下面这个mixin专门负责这件事:
@mixin stagger-delay($steps, $base: 0.1s, $increment: 0.1s) {
$delays: generate-delays($steps, $base, $increment);
@each $key, $value in $delays {
@if type-of($key) == 'number' {
&:nth-child(#{$key}) {
animation-delay: $value;
}
}
}
}
调用起来很直观:
.loader-item {
animation: fade-in 0.3s ease-out;
@include stagger-delay(5, 0.1s, 0.08s);
}
编译后生成的CSS是这样的:
.loader-item:nth-child(1) { animation-delay: 0.1s; }
.loader-item:nth-child(2) { animation-delay: 0.18s; }
.loader-item:nth-child(3) { animation-delay: 0.26s; }
/* ... */
为什么nth-child比nth-of-type更可靠?
这里有个坑需要注意:如果容器里混了其他类型的元素(比如一个 所以建议始终坚持以下几个原则: 旧版iOS Safari对大量 可以试试这几个缓解手段: 说到底,CSS预处理器不是万能胶。真正复杂的场景——比如瀑布流加载、滚动触发动画——别硬扛SCSS生成,该交JS就交JS。工具的边界要清晰,不然反而会给自己挖坑。或者一个nth-of-type会导致延迟错位——它只统计同类型标签,而nth-child严格按照DOM顺序计数。动画序列依赖的是渲染顺序,不是元素语义类型。
visibility: hidden去隐藏中间项——它仍然占据nth-child的位置,但动画不可见,很容易造成“跳帧”的错觉style.animationDelay移动端iOS Safari的卡顿问题
animation-delay叠加比较敏感。当$steps超过12的时候,可能会出现首帧卡顿或者延迟完全不生效的现象。根本原因在于浏览器对多个nth-child规则的解析开销一下子飙升了。
$steps控制在8以内,尽量用opacity + transform组合代替复杂动画will-change: transform让浏览器预分配渲染层@keyframes里写background-color渐变——重绘开销太大,优先用opacity和scale
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。