
本文详解如何利用 css 3d 变换(perspective + preserve-3d)与 scroll 事件联动,实现平滑、高性能的“纸张从插槽中迎面弹出”的视差动画,无需多图切帧,告别 class 切换陷阱。
要实现视频中那种纸张随滚动“从插槽中立体弹出、逼近用户”的 3D 效果,核心不在于切换多个图片或频繁增删 class,而在于用单一 DOM 元素 + 基于滚动进度的连续 CSS 3D 变换。这种方式更流畅、更易维护,且避免了原代码中多重 scroll 监听器嵌套、赋值运算符误用(= 应为 ===)、选择器错误('position_1' 缺少 . 或 #)、以及未定义 child 变量等常见问题。
✅ 正确思路如下:
-
结构精简:仅需一个
包裹一张纸张图片(或纯 CSS 绘制);CSS 3D 基础设置:
- 父容器添加 perspective: 1000px(定义 3D 视角深度);
- .paper 设置 transform-style: preserve-3d,确保子元素(如伪元素或内层容器)保持 3D 空间;
- 使用 translateZ() 控制前后纵深,rotateX()/rotateY() 模拟纸张倾斜,scale() 增强逼近感。
滚动驱动动画:监听 scroll 事件,将 window.scrollY 映射为 [0, 1] 范围的归一化进度值(progress),再线性或缓动映射到 translateZ、rotateX 等属性值。
示例关键代码:
/* style.css */ .slot { height: 100vh; perspective: 1200px; overflow: hidden; } .paper { width: 300px; height: 400px; margin: 0 auto; transform-style: preserve-3d; transition: transform 0.05s ease-out; /* 微延迟提升流畅感 */ } /* 初始状态:纸张在插槽后方,微倾斜 */ .paper::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: url("paper.png") center/contain no-repeat; transform: translateZ(0); } .paper { transform: translateZ(-800px) rotateX(15deg) scale(0.7); }// script.js const paper = document.querySelector('.paper'); function updatePaperPosition() { const scrollTop = window.scrollY; const maxScroll = document.body.scrollHeight - window.innerHeight; const progress = Math.min(scrollTop / maxScroll, 1); // 归一化 [0,1] // 映射滚动进度 → Z轴位移(-800px → 0px)、旋转(15° → 0°)、缩放(0.7 → 1.0) const z = -800 + progress * 800; const rotX = 15 - progress * 15; const scale = 0.7 + progress * 0.3; paper.style.transform = `translateZ(${z}px) rotateX(${rotX}deg) scale(${scale})`; } // 使用 requestAnimationFrame 优化性能(推荐) let ticking = false; window.addEventListener('scroll', () => { if (!ticking) { requestAnimationFrame(() => { updatePaperPosition(); ticking = false; }); ticking = true; } }); // 初始化一次 updatePaperPosition();⚠️ 注意事项:
- 避免在 scroll 中直接操作 style.transform 多次(原代码中重复 add/remove class 会导致重排重绘);
- 不要使用 window.scrollY === 1 这类离散判断——滚动是连续的,应使用区间映射;
- perspective 必须设在可包含子元素的父容器上(非 body 或 html),否则 3D 效果失效;
- 如需更精细控制(如插槽遮罩),可用 clip-path 或绝对定位的 ::after 插槽盖板模拟。
? 总结:真正的“滚动驱动 3D 动画”本质是将滚动位置作为输入参数,实时计算并应用连续的 CSS 变换。它比多图帧切换更轻量、比 class 切换更精准,也更符合现代 Web 动画最佳实践。从今天起,让纸张真正“飞向用户”,而不是在 DOM 中来回切换名字。










