3D 透视滚动(滚动驱动的视差纵深特效)

CSSJS 许可:自研原创

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-depth0.2-1.5,越大视差越明显
横向位移幅度translateX 中的 70px增大让层次感更夸张
侧转角度rotateY 中的 38deg建议 25-50deg,过大观感撕裂
视距.ps3d-viewperspective500-900px,影响透视强度
缩放下限scale 公式中的 0.18控制远离中心时的缩小程度

兼容性与性能

常见问题

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(缓动曲线)等属性即可,代码中有注释说明。

✍️ 作者与审核