纯 CSS 视差动画可行但需弃用 background-attachment: fixed,改用 animation-timeline: scroll() 绑定滚动时间线,通过 animation-range 控制各层触发区间与位移幅度实现层级感,配合命名时间线提升可维护性。

纯 CSS 实现视差动画现在可行,但必须放弃 background-attachment: fixed——它在 iOS Safari 和 Android Chrome 110+ 上基本被静默禁用,不是你写错了,是浏览器主动降级为 scroll。
animation-timeline: scroll() 是唯一稳定路径
现代方案依赖滚动时间线绑定动画,而非背景锚定。关键不是“让背景不动”,而是“让元素位移量随滚动进度非线性变化”。
-
animation-timeline: scroll(root)表示绑定到整个页面滚动(默认 y 轴),必须确保根容器有滚动上下文(body或html需有可滚动高度) - 不能直接驱动
transform的复合属性(如translateY+scale同时动),但可以驱动单个transform值,只要在@keyframes中显式写出起止状态 - 移动端 Safari 17.4+、Chrome 115+ 支持,旧版本需用
CSS.supports('animation-timeline', 'scroll()')检测并 fallback 到 JS 方案
animation-range 控制触发区间和速度感
视差的“层级感”不靠 z-index,而靠同一滚动时间线下不同元素的 animation-range 长度 + 关键帧位移幅度组合实现。
- 背景层建议用
animation-range: entry 0% cover 120%(拉长区间)+ 小位移(如translateY(-80px)),视觉上“慢” - 中景层用
animation-range: entry 20% cover 80%+ 中等位移(如translateY(-160px)) - 前景层用
animation-range: entry 40% cover 60%(缩窄区间)+ 大位移(如translateY(-240px)),视觉上“快” -
cover不是像素单位,是归一化滚动进度:从元素顶部进入视口到完全离开视口,全程为 100%
@scroll-timeline 命名时间线便于复用与调试
当多个元素共享同一条滚动逻辑(比如整页都基于根滚动),定义命名时间线比重复写 scroll(root) 更清晰、易维护。
立即学习“前端免费学习笔记(深入)”;
- 写法:
@scroll-timeline main-scroll { source: scroll(root); orientation: vertical; } - 使用:
animation-timeline: main-scroll; - 好处:后续想把所有视差层切换到某个
.section容器滚动,只需改一处@scroll-timeline定义,不用逐个元素调整 - 注意:
source: scroll(root)在部分安卓 WebView 中可能不生效,若遇到,显式指定source: selector(html)或source: selector(body)
真正难的不是写出第一层视差,而是让各层的入场节奏、位移曲线、缓动函数(推荐 cubic-bezier(0.25, 0.46, 0.45, 0.94))错开——这没法靠复制粘贴解决,得靠 clamp() 限幅、calc() 组合变量、反复滚动调试才稳。


















