纯CSS变量无法直接读取滚动位置,--scroll-y必须由JS注入,否则calc()会失效;移动端禁用background-attachment: fixed;需用clamp()防抖动、translateZ(0)升层优化渲染,并手动调参实现真实物理感。

纯 CSS 变量无法直接读取滚动位置,--scroll-y 必须由 JS 注入,否则所有 calc(var(--scroll-y) * 0.3) 都会计算成 NaN 或 0 —— 这是绝大多数人卡住的第一步。
为什么 --scroll-y 不能靠 CSS 自己生成
CSS 没有访问 window.scrollY 的能力,@property 也不能绑定滚动事件。所谓“纯 CSS 视差”只存在于 demo 里,真实场景中必须用 JS 把滚动值写进根元素的自定义属性。
-
--scroll-y的初始值为空或0px,不手动设就会导致calc()失效 - 移动端 Safari 和 Android Chrome 对
background-attachment: fixed的禁用,不是 bug,而是主动限制——别指望它能替代变量驱动 - 如果用了局部滚动容器(比如
overflow: auto的 div),得监听它的scrollTop,而不是window.scrollY
calc(var(--scroll-y) * var(--parallax-factor)) 的乘法陷阱
用乘法而非除法,是为了避免 --parallax-factor 为 0 或空值时整个表达式崩掉。但系数设置不当仍会导致位移失真或穿帮。
-
--parallax-factor推荐范围是0.1~0.8;负值(如-0.3)可实现反向位移 - 别在 CSS 里写死单位,比如
--parallax-factor: 0.3px—— 这会让calc()报错,应保持无单位小数 - 多个图层要各自设
style="--parallax-factor: 0.4",共用 class 容易被覆盖,且无法响应式切换
用 clamp() 防止抖动和撕裂
原始滚动值在触控板猛甩时会突变,直接乘系数会导致背景猛抽。clamp() 是最轻量的阻尼手段,比 JS 的 Math.min/max 更高效,且可被浏览器优化。
立即学习“前端免费学习笔记(深入)”;
- 写法示例:
transform: translateY(clamp(-120px, calc(var(--scroll-y) * -0.25), 0)) - 下限
-120px防止背景拉太远露出空白;上限0避免向上溢出容器顶部 -
clamp()三个参数必须同单位(全px或全rem),混用会导致整条声明被忽略
图层必须升层,否则白写
就算写了 transform: translateY(),浏览器仍可能把视差元素和普通文本合在同一个图层渲染,滚动时照样重绘、卡顿、闪烁。
- 加
transform: translateZ(0)是最稳妥的升层方式,比will-change: transform更轻量 - 别对所有视差元素一开始就加
translateZ(0),iOS Safari 上 GPU 内存容易爆;建议滚动开始后动态添加 - 父容器若设了
overflow: hidden,再套position: fixed子层会逃逸裁剪区——位移坐标就乱了
真正难的不是公式,而是让每个图层的 --scroll-y 偏移节奏错开:背景慢、中景中速、前景快,还要各自配不同 cubic-bezier() 曲线。变量只是管道,物理感来自你对速度、加速度、阻尼系数的手动调参,而不是复制粘贴一段代码就能出来。


















