如何复刻Refokus式滚动触发垂直卡片滑块?
垂直卡片滑块复刻实现(滚动触发图片滑入)
核心原理拆解
- 利用CSS
perspective和transform-style: preserve-3d构建3D视觉空间,让卡片滑动带有立体层次感 - 通过监听
scroll事件,实时计算页面滚动偏移量,映射为卡片的translate位移和rotate旋转值,实现滚动驱动的滑入动画 - 卡片初始状态设置为完全移出视口(结合垂直位移与旋转角度),随着滚动逐步恢复到正常展示位置
完整实现代码
HTML结构
<div class="slider-container"> <div class="card"> <div class="card-inner"> <img src="https://picsum.photos/seed/card1/800/1200" alt="卡片1"> </div> </div> <div class="card"> <div class="card-inner"> <img src="https://picsum.photos/seed/card2/800/1200" alt="卡片2"> </div> </div> <div class="card"> <div class="card-inner"> <img src="https://picsum.photos/seed/card3/800/1200" alt="卡片3"> </div> </div> <div class="card"> <div class="card-inner"> <img src="https://picsum.photos/seed/card4/800/1200" alt="卡片4"> </div> </div> </div>
CSS样式
/* 全局重置 */ * { margin: 0; padding: 0; box-sizing: border-box; } body { height: 400vh; /* 足够长的滚动高度 */ perspective: 1000px; /* 核心:创建3D透视空间 */ overflow-x: hidden; } .slider-container { position: fixed; top: 0; left: 50%; transform: translateX(-50%); width: 80%; max-width: 800px; height: 100vh; transform-style: preserve-3d; /* 子元素继承3D空间 */ } .card { position: absolute; width: 100%; height: 70vh; top: 15vh; border-radius: 16px; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.3); transition: transform 0.1s ease-out; /* 平滑过渡动画 */ } .card-inner { width: 100%; height: 100%; transform-style: preserve-3d; } .card img { width: 100%; height: 100%; object-fit: cover; } /* 初始状态:卡片移出视口并带旋转 */ .card:nth-child(1) { transform: translateY(100vh) rotateX(-20deg); z-index: 4; } .card:nth-child(2) { transform: translateY(100vh) rotateX(-20deg); z-index: 3; } .card:nth-child(3) { transform: translateY(100vh) rotateX(-20deg); z-index: 2; } .card:nth-child(4) { transform: translateY(100vh) rotateX(-20deg); z-index: 1; }
JavaScript逻辑
const cards = document.querySelectorAll('.card'); const cardCount = cards.length; const triggerOffset = window.innerHeight * 0.2; // 提前触发动画的偏移阈值 window.addEventListener('scroll', () => { const scrollY = window.scrollY; // 每张卡片对应的滚动区间长度 const cardScrollRange = (document.body.scrollHeight - window.innerHeight) / cardCount; cards.forEach((card, index) => { // 当前卡片的滚动触发起始点 const startScroll = index * cardScrollRange; // 计算当前卡片的动画进度(0-1区间) const progress = Math.min(Math.max((scrollY - startScroll + triggerOffset) / cardScrollRange, 0), 1); // 根据进度计算位移和旋转值 const translateY = (1 - progress) * 100; const rotateX = (1 - progress) * -20; card.style.transform = `translateY(${translateY}vh) rotateX(${rotateX}deg)`; }); });
关键细节调整
perspective值可按需修改:数值越小,3D立体效果越强- 卡片
z-index层级设置确保滚动时的叠放顺序,避免视觉混乱 - 调整
cardScrollRange可以控制单张卡片滑入动画对应的滚动距离 triggerOffset参数可修改动画触发的提前量,优化滚动交互体验
内容的提问来源于stack exchange,提问作者mindprojx
相关产品推荐
相关产品推荐

