现代浏览器(如iOS Safari 15+、Chrome)为性能禁用background-attachment: fixed,可靠方案是JS+requestAnimationFrame动态计算transform位移,或严格满足父容器无transform/overflow且背景设cover/center。

视差滚动需要 CSS background-attachment: fixed,但现代浏览器对 fixed 在滚动容器中的行为有变化
直接在 上设 background-attachment: fixed 曾经是主流做法,但现在 Safari(iOS 15+)和部分 Chrome 版本会禁用该效果以提升滚动性能,导致视差“失效”。真正可靠的方式是用 transform: translateY() 配合 JS 监听 scroll 事件做位移计算,或者用 CSS will-change: transform + transform 触发硬件加速。
如果你坚持纯 CSS 方案,必须满足两个条件:父容器不能有 overflow: hidden 或 transform 属性;背景图需设为 background-size: cover 且 background-position: center。否则即使写了 fixed,视觉上也看不出层次移动。
requestAnimationFrame 比 scroll 事件更稳,尤其防抖和节流不是万能的
用 addEventListener('scroll', ...) 直接绑定滚动监听,容易在快速滑动时丢帧或卡顿——因为浏览器可能合并多次 scroll 事件,也可能在非主线程触发,导致视差位移滞后。更稳妥的做法是只在 scroll 里标记“需要更新”,再用 requestAnimationFrame 去读取 window.scrollY 并更新元素 transform。
- 不要在 scroll 回调里直接操作 DOM 样式,尤其是
style.transform - 把视差层封装成对象,每个层存自己的
speed(如 0.2 表示滚动 100px,它只移动 20px) - 用
getBoundingClientRect().top判断层是否进入视口,避免对不可见区域做无意义计算
404 页面结构要轻量,别让视差拖慢首屏渲染
一个带视差的 404 页面,DOM 节点建议控制在 5 个以内:一个全屏背景层、一个中景文字容器(含 <h1>404</h1>)、一个前景装饰元素(比如漂浮的图标)、一个返回按钮、一个可选的微动云朵组(用 @keyframes 循环动画)。再多就容易触发重排,尤其在低端 Android 设备上。
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
所有视差图都应内联为 base64(小图)或用 loading="lazy"(大图),禁止在 上写 background-image: url(...) 加载未压缩的 PNG —— 这会让 404 页面比主站还慢。
- 文字层建议用
position: relative+z-index,不依赖transform,保证可读性不受 GPU 渲染异常影响 - 避免给视差层加
box-shadow或filter: blur(),这两者在移动端耗性能极高 - 用
@media (prefers-reduced-motion: reduce)关掉动画和视差,这是 WCAG 2.1 强制要求
移动端 Safari 的 scroll-behavior: smooth 和视差冲突,得手动降级
如果你在 404 页面加了“回到首页”按钮并用了 scroll-behavior: smooth,Safari 会强制将整个页面切到新的滚动上下文,导致 transform 视差层错位甚至消失。这不是 bug,是 WebKit 对滚动优化的副作用。
解决方式很简单:检测 navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome'),然后对 Safari 移动端禁用 smooth scroll,并把视差更新逻辑从 requestAnimationFrame 改为 touchmove + passive: false 监听(注意要 preventDefault 否则 touch 不触发)。
另外,iOS 上 document.scrollingElement.scrollTop 不可靠,一律改用 window.pageYOffset。
will-change: transform 的时机——它不该一开始就加在元素上,而应在用户开始滚动后才动态添加,滚动停止 100ms 后再移除,否则长期占用 GPU 内存。


















