background-attachment: fixed 不适合做带阻尼感的视差,因其仅支持固定或滚动两种状态,无法模拟惯性或减速回弹,且易被 transform 等属性静默失效;真正可控的阻尼需用 JS + requestAnimationFrame 计算插值偏移并以 transform 渲染。

background-attachment: fixed 不适合做“带阻尼感”的视差
它只支持“固定 or 滚动”两种状态,没有中间速度可调,更无法模拟物理惯性或减速回弹。现代浏览器(Chrome v99+、所有 Safari)在绝大多数场景下会静默降级为 scroll,连报错都没有。哪怕你写对了 background-attachment: fixed,只要父元素有 transform、filter、opacity: 0.99 或 will-change,它就直接失效。
用 transform + requestAnimationFrame 模拟阻尼滚动
真正可控的阻尼感必须靠 JS 计算滚动位移并插值,CSS 只负责渲染。核心是把滚动位置映射成带缓动系数的偏移量,再用 transform: translateY() 渲染,避免触发布局重排。
- 监听
scroll事件时,**不要直接改style.top或style.backgroundPosition** —— 这会强制同步重排,卡顿明显 - 改用
requestAnimationFrame包裹更新逻辑,确保每帧只执行一次渲染 - 用
getBoundingClientRect().top判断元素是否进入视口,比单纯依赖window.scrollY更稳定(尤其页面有 sticky header 时) - 阻尼公式常用:
offset = (targetY - currentY) * 0.15,其中0.15是阻尼系数,越小越“沉”,越大越跟手 - 前景层系数设为
0.3,中景0.15,背景0.05,就能自然形成近快远慢 + 惯性拖尾感
perspective + translateZ 方案不支持阻尼,仅适合纯 CSS 视差
这个方案能做出多层纵深感,但它是静态的——滚动时各层位移与 scrollTop 成严格线性关系,没有任何缓冲或延迟。你设了 perspective: 1px 和 transform: translateZ(-1px),浏览器就按透视规则自动算出位移,没法中途插入 easing 函数。
- 它适合“一次性加载、不交互、不需响应式微调”的静态展示页
- 一旦你要做“滚动到某区域才启动视差”“移动端降级为无视差”“用户快速滚动后图层慢慢归位”,就必须切回 JS 方案
-
transform-style: preserve-3d和scale()补偿缩放是必须的,漏掉会导致图层视觉尺寸异常缩小
移动端阻尼视差必须降级处理
iOS Safari 对 background-attachment: fixed 基本无视,对高频 scroll 事件也做节流(每 200ms 才触发一次),直接套桌面端逻辑会卡顿或完全不动。
立即学习“前端免费学习笔记(深入)”;
- 检测
'ontouchstart' in window或matchMedia('(hover: none) and (pointer: coarse)')来判断触屏设备 - 触屏设备上,把阻尼系数从
0.15提高到0.3,减少视觉延迟感 - 禁用
passive: false的 scroll listener,改用{ passive: true }避免被浏览器强制取消 - 图层元素加
will-change: transform(仅限真正需要动画的层),但别滥用,否则内存暴涨
真正难的不是写出第一版阻尼视差,而是让不同设备、不同滚动速度、不同 DOM 加载时机下,各层偏移始终对齐且不跳变。建议把阻尼计算逻辑抽成独立函数,传入当前 scrollTop、目标 offset、上一帧 timestamp,再统一输出平滑 y 值——这样后续加弹簧物理模型或手势拖拽也能复用。


















