纯css视差核心是transform: translatez()触发3d上下文,配合perspective与preserve-3d实现景深差异;ios safari不支持background-attachment: fixed,需改用position: absolute多层容器或轻量js+防抖更新transform。

用 transform: translateZ() 触发 3D 上下文是关键
纯 CSS 实现视差,核心不是“滚动监听”,而是利用 transform: translateZ() 让不同层在 3D 空间中处于不同景深,再配合 transform: translateX/Y() 的相对位移差异来模拟速度差。浏览器会自动根据 Z 轴位置缩放和偏移元素(需父容器设 transform-style: preserve-3d 和 perspective)。
常见错误是只加 translateY 并试图用 scroll-behavior 或 JS 控制——那只是动画,不是视差;真视差必须有 Z 轴参与。
- 父容器必须设
perspective: 1px(值越小,视差越强;但太小会导致元素缩得太小) - 每层背景需设
transform-style: preserve-3d(通常放在滚动容器上) - 各层用
transform: translateZ(-1px) translateY(0)这类组合,Z 值为负且互不相同(如 -1px、-2px、-4px) - 背景图必须用
background-attachment: fixed或脱离文档流(否则滚动时会“拖拽”)
background-attachment: fixed 在 iOS Safari 上基本失效
iOS Safari(尤其 iOS 15+)对 background-attachment: fixed 支持极差,即使开启硬件加速也常回退为 scroll,导致视差完全不生效。这不是 bug,是 Safari 主动禁用该属性以保滚动性能。
绕过方式只有两个:一是改用 position: sticky + 多层绝对定位容器;二是用轻量 JS 监听 scroll 并更新 transform ——但后者要防抖、节流、用 passive: true,否则卡顿明显。
立即学习“前端免费学习笔记(深入)”;
- 纯 CSS 方案在 iOS 上建议放弃
fixed,改用多层position: absolute容器 +top: 0+width/height: 100% - 若用 JS,只更新
style.transform,别触发布局(避免读取offsetTop等) - 务必加
will-change: transform到每一层,提示浏览器提前 GPU 加速
层级顺序和 z-index 容易反直觉
视差层的视觉前后关系,不完全由 z-index 决定,更取决于 3D 空间中的 Z 坐标:Z 值越负(如 -4px),离用户越远,看起来越“靠后”,移动也越慢;Z 值越接近 0(如 -0.5px),越“靠前”,移动越快。但 DOM 渲染顺序仍受 z-index 影响,二者冲突就会穿帮。
典型穿帮现象:远处山峦盖住了近处树木——其实是 DOM 中山峦元素写在了树木前面,又没设足够高的 z-index 补偿。
- 确保 DOM 顺序从远到近排列(最远层最先写)
- 给每层设明确
z-index,且与 Z 轴逻辑一致(如translateZ(-4px)对应z-index: 1,translateZ(-1px)对应z-index: 3) - 所有层必须同级(不能嵌套),否则
preserve-3d不生效
滚动容器必须设 overflow-y: scroll 且有明确高度
视差效果依赖滚动事件或 3D 透视投影,如果滚动容器是 body,在多数现代浏览器里会被优化掉部分渲染行为(比如 Chrome 对 body 滚动的合成层处理很激进),导致位移卡顿或错位。
更稳定的做法是把视差限制在一个有明确 height 和 overflow-y: scroll 的 div 内,并设 scroll-behavior: smooth(可选)。
- 不要用
html或body作为滚动容器(iOS 尤其敏感) - 容器高度不能是
min-height或依赖内容撑开,必须是固定值或100vh - 若需全屏视差,用
height: 100vh+overflow-y: scroll,并确保内部内容高度 > 100vh










