3D 透视滚动(滚动驱动的视差纵深特效)
3D 透视滚动组件:内嵌滚动容器内卡片随滚动位置产生位移、旋转与缩放,深度越大的卡片视差越明显,滚动监听零依赖自研实现,参数全部可调。
效果演示(真实可交互)
在演示区上下滚动,观察不同 data-depth 深度值的卡片:深度越大,卡片横向偏移越远、绕 Y 轴侧转角度越大,同时远离视口中心时还会缩小,营造出「近大远小」的纵深空间感。滚动到中间位置的卡片最正、最清晰,两侧卡片则倾斜着「看向」观者。
第一层 · 视差最明显
第二层 · 中等深度
第三层 · 近景微动
第四层 · 深空感
第五层 · 缓慢漂移
第六层 · 最抢眼
上下滚动容器,观察不同 depth 深度下卡片的位置偏移与 3D 旋转差异
完整代码
HTML(每张卡片用 data-depth 声明自己的深度):
<div class="ps3d-scroll">
<div class="ps3d-view">
<div class="ps3d-item" data-depth="1.2">第一层</div>
<div class="ps3d-item" data-depth="0.5">第二层</div>
<div class="ps3d-item" data-depth="0.2">第三层</div>
</div>
</div>
CSS(滚动容器与 3D 上下文):
.ps3d-scroll { height: 280px; overflow-y: auto; }
.ps3d-view {
perspective: 700px; /* 3D 旋转的视距 */
transform-style: preserve-3d;
}
.ps3d-item { will-change: transform; }
JS(滚动位置驱动 transform,核心约 15 行):
const scroller = document.querySelector('.ps3d-scroll');
const items = scroller.querySelectorAll('.ps3d-item');
const update = () => {
const rect = scroller.getBoundingClientRect();
const center = rect.top + rect.height / 2;
items.forEach((item) => {
const r = item.getBoundingClientRect();
const mid = r.top + r.height / 2;
const t = (mid - center) / (rect.height / 2); // 居中为 0,越界裁剪到 ±1
const d = parseFloat(item.dataset.depth || '1');
const clamped = Math.max(-1, Math.min(1, t));
item.style.transform = [
`translateX(${clamped * d * 70}px)`, // 横向视差位移
`rotateY(${clamped * d * 38}deg)`, // 深度越深侧转越大
`rotateX(${clamped * d * 6}deg)`,
`scale(${1 - Math.min(Math.abs(clamped), 1) * 0.18})`
].join(' ');
});
};
scroller.addEventListener('scroll', update, { passive: true });
update();
思路非常直接:每个滚动帧里计算卡片中心相对滚动容器中心的归一化距离(-1 到 1),再乘以该卡片的深度系数,得到位移、旋转与缩放。深度系数就是「视差放大器」,一套公式吃遍所有层。
参数说明
| 参数 | 位置 | 说明 |
|---|---|---|
| 深度系数 | 卡片的 data-depth | 0.2-1.5,越大视差越明显 |
| 横向位移幅度 | translateX 中的 70px | 增大让层次感更夸张 |
| 侧转角度 | rotateY 中的 38deg | 建议 25-50deg,过大观感撕裂 |
| 视距 | .ps3d-view 的 perspective | 500-900px,影响透视强度 |
| 缩放下限 | scale 公式中的 0.18 | 控制远离中心时的缩小程度 |
兼容性与性能
- 只依赖
perspective与transform,Chrome 31+ / Safari 9+ / Firefox 36+ / Edge 全支持 - scroll 监听使用 passive 模式,不阻塞滚动线程;transform 走合成层,GPU 加速
- 卡片数量建议控制在 20 张以内;本组件使用内嵌滚动容器,也适合整页滚动的首屏场景,只要把 scroller 换成 window 并监听其 scroll 即可
- 移动端惯性滚动同样触发 scroll 事件,效果一致;若卡片带图片,建议压缩后使用
常见问题
Q: 卡片滚出容器边缘时被裁切或出现锯齿? 检查滚动容器是否设置了 overflow 裁切相关属性;另外 perspective 写在 .ps3d-view 上而不要写在每张卡片上,否则旋转基准各自独立,空间感会乱。
Q: 为什么有的卡片没有视差效果? 大概率是 data-depth 没写或解析失败,parseFloat 会回退为默认值 1;也可以检查 transform 是否被其他内联样式覆盖。
Q: 滚动时画面闪烁或掉帧? 尝试给卡片加 will-change: transform,并确认卡片数量、阴影等重绘成本可控。阴影较重的卡片可考虑去掉 box-shadow 或改用伪元素渐变。
Q: 能商用吗? 可以。本组件为粤喵自研原创实现,免费商用无需署名。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。