如何通过页面滚动添加/移除类实现3D纸张弹出动画?
滚动控制纸张弹出3D动画实现方案
我需要实现一个动画:用户向下滚动页面时,一张纸张从插槽中向屏幕前弹出的3D效果,滚动操作控制纸张的进出。
我尝试过用多张代表不同弹出阶段的图片,通过滚动时添加/移除类来切换,但这个方法没法实现流畅动画,求最优解决方案。
我尝试的代码
HTML
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Scroll card flip</title> <link rel="stylesheet" href="style.css"> <body> <section class="one"> <div class="parent"> <div class="position_1"> <img src="position_1.png"> </div> <div class="position_2"> <img src="position_2.png"> </div> <div class="position_2"> <img src="position_2.png"> </div> <div class="position_3"> <img src="position_3.png"> </div> <div class="position_4"> <img src="position_4.png"> </div> <div class="position_5"> <img src="position_5.png"> </div> <div class="position_6"> <img src="position_6.png"> </div> </div> </section> <section class="two"> </section> <section class="three"> </section> <script src="script.js"></script> </body> </html>
CSS
* { padding: 0; margin: 0; } section { height: 100vh; overflow: hidden; } .parent { width: 100vw; height: 100vh; display: flex; justify-content: center; place-items: center; } .one { background-color: greenyellow; } .two { background-color: orangered; } .three { background-color: aqua; }
JavaScript
window.addEventListener('scroll', () => { const position_1 = document.querySelector('position_1'); if(window.scrollY = 1) { child.classList.add('position_1');} else if(window.scrollY = 2){ child.classList.remove('position_1'); } if(window.scrollY = 2) { child.classList.add('position_2'); } else if(window.scrollY = 3){ child.classList.remove('position_2'); } if(window.scrollY = 3) { child.classList.add('position_3'); } else if(window.scrollY = 4){ child.classList.remove('position_3'); } if(window.scrollY = 4) { child.classList.add('position_4'); } else if(window.scrollY = 5){ child.classList.remove('position_4'); } if(window.scrollY = 5) { child.classList.add('position_5'); } else if(window.scrollY = 6){ child.classList.remove('position_5'); } if(window.scrollY = 6) { child.classList.add('position_6'); } window.addEventListener('scroll',()=>{ const scrolled = window.scrollY; console.log(scrolled); });})
最优解决方案
你的方法问题在于用离散的图片切换,很难做到流畅,而且JS逻辑里存在语法错误(比如用=赋值而非==/===判断、重复绑定scroll事件、child变量未定义等)。推荐用CSS 3D变换结合滚动监听,用单个元素实现连续动画:
实现思路
- 用单个纸张元素,通过CSS
transform的translateZ(控制前后位置)、rotateX(模拟弹出角度)实现3D效果 - 监听滚动事件,根据滚动距离计算动画进度,动态更新纸张的变换属性
- 父容器开启
perspective属性,营造3D空间感
完整代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Scroll Paper Popup</title> <link rel="stylesheet" href="style.css"> </head> <body> <section class="paper-section"> <div class="slot"> <div class="paper"> <div class="paper-content"> 这是弹出的纸张 </div> </div> </div> </section> <section class="placeholder-section"></section> <section class="placeholder-section"></section> <script src="script.js"></script> </body> </html>
CSS
* { padding: 0; margin: 0; box-sizing: border-box; } section { height: 100vh; } .paper-section { background-color: greenyellow; display: flex; justify-content: center; align-items: center; perspective: 800px; overflow: hidden; } .slot { width: 300px; height: 400px; border: 3px solid #333; border-radius: 8px; position: relative; overflow: hidden; background-color: #fff; } .paper { width: 280px; height: 380px; background-color: #f9f9f9; position: absolute; top: 10px; left: 10px; transform-origin: bottom center; transition: transform 0.1s ease-out; box-shadow: 0 2px 10px rgba(0,0,0,0.2); } .paper-content { padding: 20px; font-size: 18px; color: #333; } .placeholder-section:nth-child(2) { background-color: orangered; } .placeholder-section:nth-child(3) { background-color: aqua; }
JavaScript
const paper = document.querySelector('.paper'); const paperSection = document.querySelector('.paper-section'); const sectionTop = paperSection.offsetTop; const sectionHeight = paperSection.offsetHeight; const windowHeight = window.innerHeight; const scrollRange = sectionHeight + windowHeight; window.addEventListener('scroll', () => { const scrollY = window.scrollY; let progress = (scrollY - sectionTop + windowHeight) / scrollRange; progress = Math.max(0, Math.min(1, progress)); const translateZ = progress * 200; const rotateX = progress * -30; paper.style.transform = `translateZ(${translateZ}px) rotateX(${rotateX}deg)`; });
说明
- 这个方案用连续的3D变换替代离散的图片切换,动画更流畅自然
- 滚动进度和动画参数可以根据需求调整(比如
translateZ的最大值、rotateX的角度) - 插槽和纸张的尺寸、样式可以自定义,适配你的设计需求
内容的提问来源于stack exchange,提问作者Jen
相关产品推荐
相关产品推荐

