逐行渐显需用animation-delay配合opacity或transform实现,因visibility和display不可动画;nth-child(n)延迟应为(n-1)*step;需确保每行是独立块级元素;移动端需控制行数≤10并避免干扰图层合成。

直接用 animation-delay 控制每行文字的入场时机,是实现逐行渐显最轻量、最可控的方式——前提是每行必须是独立的块级元素,且动画属性可被延迟触发。
为什么 nth-child(n) 必须配合 opacity 或 transform
只写 visibility: hidden → visible 或 display: none → block 不会动,因为这两个属性不可动画。浏览器对它们的切换是立即生效的,animation-delay 会“挂起”但不产生过渡效果。
真正起作用的是 opacity(从 0 到 1)或 transform(如 translateY(10px) → translateY(0)),它们属于可动画属性,能响应 animation-delay 并平滑过渡。
- 推荐组合:
opacity: 0; transform: translateY(4px); animation: fadeInUp 0.4s forwards; - 对应
@keyframes中必须包含from和to的完整状态定义 - 别漏掉
forwards,否则动画结束瞬间会回退到初始态
nth-child(n) 的延迟值怎么算才不翻车
nth-child(n) 的 n 是从 1 开始计数的,第 1 行对应 n=1,所以延迟应为 (n - 1) * step,不是 n * step。
立即学习“前端免费学习笔记(深入)”;
手动写死容易错,也难维护。更稳妥的是用 CSS 自定义属性统一控制步长:
.line-reveal { animation: fadeInUp 0.4s forwards; }
.line-reveal:nth-child(n) {
animation-delay: calc((n - 1) * var(--delay-step));
}
/* 在父容器上设 */
.line-container {
--delay-step: 0.15s;
}
- 避免用
ms和s混用,统一用s(如0.15s而非150ms) - 旧版 Safari 和 IE 不支持小数秒的
animation-delay,建议用一位小数(0.1s、0.2s),并加-webkit-animation-delay前缀 -
calc()里不能用 CSS 变量做乘数(如calc(var(--i) * 0.1s)),变量只能用于被乘数位置
动态生成内容时,换行符怎么变成独立行
从 <textarea></textarea> 或 API 拿到的文本含 \n,但 HTML 默认忽略它。直接 split('\n') 后塞进 <span></span>,所有行仍挤在一行里,nth-child 失效。
正确做法是让每行成为块级、同级、可被 nth-child 选中的元素:
- 服务端或 JS 处理:用
text.split('\n').map(line => `<div class="line-reveal">${line}</div>`).join('') - 确保父容器不设
white-space: nowrap,也不用display: inline类样式 - 若必须保留原始 HTML 结构,可用
display: block强制每个<span></span>换行,但语义不如<div> 清晰<h3>移动端 Safari 的掉帧和兼容性陷阱</h3> <p>iOS Safari 对连续多个 <code>nth-child+animation-delay的渲染压力较大,超过 10 行就可能卡顿或跳帧。这不是代码写错了,是 WebKit 的合成层调度限制:
- 限制单次动画行数在 8–10 行以内,更多内容建议分段触发(比如点击“展开”后再启动后 5 行)
- 别给每行加
will-change: opacity,批量设置会导致内存飙升;只在真正要动的容器上加 - 避免父容器有
filter、transform或opacity ,这些会干扰子元素动画的图层合并
逐行渐显看着简单,真正落地时最容易栽在 DOM 结构、单位精度和移动端合成策略这三处。尤其是
nth-child的索引偏移和 Safari 对小数延迟的容忍度,不实测很容易上线才发现第一行也延迟了。


















