background-attachment: fixed 在多数场景下失效,仅在 body 上且无层叠上下文样式时有效;移动端基本不可用;推荐用 transform: translateZ() + perspective 或 position: fixed DOM 层模拟视差。

background-attachment: fixed 在绝大多数实际页面中根本不会生效——不是你漏写了 background-image,也不是没设 height,而是浏览器主动把它当摆设了。
为什么 background-attachment: fixed 总是“不动”
它只在极窄条件下能跑通:必须直接写在 body 上,且 body 不能有任何触发层叠上下文的样式。一旦父级或自身加了 transform、filter、opacity: 0.99 或 will-change,Chrome v99+ 和所有 Safari 就静默降级为 scroll,控制台连 warning 都不抛。
-
background-attachment只对设置了background-image的元素起效;纯色或渐变背景也得显式声明图片(哪怕用url("data:image/svg+xml,")占位) - 移动端 iOS Safari 几乎完全无视该属性,哪怕写在
body上也大概率退化 - 容器靠内容撑高(比如没设
height或min-height),视差行为会直接消失
真正在生产环境能用的纯 CSS 替代方案
用 transform: translateZ() + perspective 是目前最可控、兼容性最好的纯 CSS 多层视差方案。原理是利用 3D 空间中的 Z 轴距离差异,让不同层级在滚动时自然产生速度差。
- 给外层容器设
perspective: 1px(值越小,视差越强) - 各视差层分别设
transform: translateZ(-0.5px)、translateZ(-1px)等负值,越负越“远”,滚动时移动越慢 - 必须配套
transform-style: preserve-3d,否则子元素会被拍平 - 要补偿因 Z 轴缩放导致的尺寸变化,加
scale(2)或类似值手动拉回原大小
用 position: fixed DOM 层模拟视差的实操要点
放弃“背景图固定”思路,改用真实 DOM 层模拟深度。每层都是独立 position: fixed 元素,手动驱动位移:
- 所有视差层统一设
position: fixed; top: 0; left: 0; width: 100%; height: 100vh; - 用
z-index显式排序:远层z-index: 1、中层z-index: 10、近层z-index: 100 - 滚动时只改
transform: translateY(),例如layer.style.transform = `translateY(${scrollY * 0.3}px)` - 绝对不要用
top或margin-top驱动——触发 layout,iOS 上一卡一个准 - 每层加
will-change: transform,但只在开始滚动后动态添加,避免空转耗资源
移动端必须做的降级处理
别指望 fixed 在手机上工作。真要上线,必须用 @supports not (background-attachment: fixed) 做兜底,或者直接按 UA 判断 iOS/Android。
- 降级后改用
background-attachment: scroll+background-size: 100% auto,防止图片被拉伸变形 - 如果用了 JS 方案,记得加
if (!el.offsetParent) return;,防止元素未挂载或display: none时报错 - 滚动监听必须包裹在
requestAnimationFrame中,否则 iOS Safari 会掉帧
真正难的不是让某一层“看起来不动”,而是让多层之间保持稳定的速度比——这需要精确控制 Z 轴距离与 scale 补偿的配合,稍有偏差就容易出现缩放失真或层级错位。很多项目卡在这里,不是代码写错了,而是没意识到 translateZ(-1px) 和 scale(2) 是绑定关系,不能单独调。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











