You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;

关键部分解释

  1. 初始堆叠设置:用gsap.set()给除第一张外的卡片设置缩小、下移、半透明的初始状态,同时通过zIndex控制堆叠层级,让后面的卡片在更底层
  2. ScrollTrigger配置:scrub: true让动画进度和滚动进度绑定,实现滚动时的平滑过渡;start和end设置每个卡片切换的滚动触发范围
  3. 动画逻辑:每个触发点触发时,当前卡片退到堆叠层,下一张卡片放大到前景,同时调整zIndex确保当前卡片在最上层
  4. 容器样式:设置固定高度h-[600px]和相对定位,确保卡片能绝对定位堆叠,同时给足够的滚动空间

调试与优化

  • 如果触发位置不对,可以调整start和end里的百分比值,或者修改容器的py、h等Tailwind类来调整滚动范围
  • 可以修改scale、y的数值来调整堆叠的紧凑程度
  • 调试时可以打开markers: true,查看ScrollTrigger的触发起始点,方便调整

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:13:02