如何在React+Tailwind项目中复刻Codepen上的Babel堆叠卡片滚动动画效果
如何在React+Tailwind项目中复刻Codepen上的Babel堆叠卡片滚动动画效果
看起来你用了react-stacked组件,但它的默认效果和你想要的那种3D堆叠滚动(一次一张高亮显示,滚动时切换带缩放层级变化)不匹配对吧?既然已经装了GSAP,咱们可以直接用GSAP+ScrollTrigger来手动实现这个效果,完全复刻你说的Codepen那种卡片堆叠滚动的交互。
实现步骤与完整代码
1. 核心思路
- 所有卡片初始堆叠在同一位置,仅第一张为正常大小,其余缩小、下移并降低层级,形成堆叠效果
- 用GSAP的ScrollTrigger监听滚动进度,触发卡片的缩放、位置、层级切换动画
- 绑定滚动与动画进度,实现滚动时平滑的卡片切换过渡
2. 完整组件代码
import { useEffect, useRef } from 'react'; import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); const industries = [ { name: 'Healthcare', icon: '', description: 'HIPAA-compliant solutions for providers and payers' }, { name: 'Finance', icon: '', description: 'Secure fintech and banking solutions' }, { name: 'E-commerce', icon: '', description: 'Scalable platforms for online retailers' }, { name: 'Education', icon: '', description: 'EdTech solutions for institutions and learners' }, { name: 'Manufacturing', icon: '', description: 'Industry 4.0 and smart factory solutions' }, { name: 'Logistics', icon: '', description: 'Supply chain optimization and tracking' }, ]; const IndustriesStackScroll = () => { const cardsContainerRef = useRef(null); const cardsRef = useRef([]); useEffect(() => { const cards = cardsRef.current; if (!cards.length) return; // 初始状态设置:堆叠卡片 gsap.set(cards.slice(1), { scale: 0.8, y: 40, opacity: 0.9, zIndex: (i) => cards.length - i - 1, }); // 为每个卡片创建滚动触发动画 cards.forEach((card, index) => { if (index === cards.length - 1) return; // 最后一张不需要触发下一个 const nextCard = cards[index + 1]; gsap.timeline({ scrollTrigger: { trigger: cardsContainerRef.current, start: `top ${index * 30}%`, // 每个卡片的触发起点 end: `top ${(index + 1) * 30}%`, scrub: true, // 滚动与动画绑定,平滑过渡 markers: false, // 调试时可以打开,查看触发点 }, }) // 当前卡片退到堆叠层 .to(card, { scale: 0.8, y: 40, opacity: 0.9, zIndex: cards.length - index - 1, duration: 0.5, }) // 下一张卡片放大到前景 .to(nextCard, { scale: 1, y: 0, opacity: 1, zIndex: cards.length, duration: 0.5, }, 0); // 0表示和上一个动画同时开始 }); // 清理函数 return () => { ScrollTrigger.getAll().forEach(trigger => trigger.kill()); }; }, []); return ( <div className="w-full max-w-4xl mx-auto py-24"> <h2 className="text-4xl font-bold text-center mb-16">Industries We Serve</h2> {/* 卡片容器:相对定位,让卡片绝对定位堆叠 */} <div ref={cardsContainerRef} className="relative w-full h-[600px] overflow-hidden" > {industries.map((industry, index) => ( <div key={industry.name} ref={el => cardsRef.current[index] = el} className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-4/5" > <div className="bg-gray-800 text-white p-8 rounded-xl shadow-lg text-center"> <div className="text-5xl mb-4">{industry.icon}</div> <h3 className="text-2xl font-bold mb-2">{industry.name}</h3> <p className="text-gray-300">{industry.description}</p> </div> </div> ))} </div> </div> ); }; export default IndustriesStackScroll;
关键部分解释
- 初始堆叠设置:用
gsap.set()给除第一张外的卡片设置缩小、下移、半透明的初始状态,同时通过zIndex控制堆叠层级,让后面的卡片在更底层 - ScrollTrigger配置:
scrub: true让动画进度和滚动进度绑定,实现滚动时的平滑过渡;start和end设置每个卡片切换的滚动触发范围 - 动画逻辑:每个触发点触发时,当前卡片退到堆叠层,下一张卡片放大到前景,同时调整
zIndex确保当前卡片在最上层 - 容器样式:设置固定高度
h-[600px]和相对定位,确保卡片能绝对定位堆叠,同时给足够的滚动空间
调试与优化
- 如果触发位置不对,可以调整
start和end里的百分比值,或者修改容器的py、h等Tailwind类来调整滚动范围 - 可以修改
scale、y的数值来调整堆叠的紧凑程度 - 调试时可以打开
markers: true,查看ScrollTrigger的触发起始点,方便调整
内容来源于stack exchange
相关产品推荐
相关产品推荐

