본문 바로가기
React

[React] GSAP ScrollTrigger 라이브러리 사용해 스크롤에 반응하는 애니메이션 구현하기

by teamnova 2025. 8. 4.
728x90

안녕하세요 오늘은 GSAP ScrollTrigger 라이브러리를 활용하여 사용자의 스크롤에 따라 

컴포넌트에 애니메이션을 추가해보도록 하겠습니다. 

https://gsap.com/docs/v3/Plugins/ScrollTrigger

 

GSAP ScrollTrigger  은 "스크롤 위치에 맞춰 애니메이션을 재생·스크럽·핀·스냅까지 제어” 해 주는 GSAP 플러그인입니다. 

 

 

먼저 components 디렉토리 내부에 (디렉토리가 없다면 "프로젝트 루트/src" 안에 만들어줍니다) FadeInSection.jsx 파일을 만들어줍니다. 

 

 

1. FadeInSection.jsx

import { useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(ScrollTrigger);

export default function FadeInSection({ children}) {
  const section = useRef(null);

  useGSAP(
    () => {
      gsap.fromTo(
        section.current,
        { opacity: 0, y: 40 },
        {
          opacity: 1,
          y: 0,
          duration: 0.8,
          ease: "power2.out",

          // ───────── ScrollTrigger 옵션 ─────────
          scrollTrigger: {
            trigger: section.current,
            start: "top 80%",          // 섹션 top 이 뷰포트 80% 위치에 닿을 때
            toggleActions: "play none none reverse",
            scrub: true            // 스크롤 속도에 맞춰 부드럽게
          }
        }
      );
    },
    { scope: section }               // 자동 클린업
  );

  return (
    <div ref={section} className="p-6 bg-white dark:bg-gray-800 rounded shadow">
      {children}
    </div>
  );
}

 

 

- scrub : true -> toggleActions: "play none none reverse" 의 reverse 설정으로 인해 스크로를 위로 올려 섹션을 벗어날 때 애니메이션이 반대로 진행 된다. 

 

- scope : section -> scope 은 DOM 노드 아래에서 만든 GSAP 애니메이션, ScrollTrigger를 한 그룹으로 묶어줍니다. 컴포넌트가 언마운트 되면 context.revert()가 자동 호출돼 타임라인, 트리거, 이벤트가 전부 해제됩니다.

 

 

 

2. App.jsx 

function App() {
  const { scrollYProgress } = useScroll();

  return (
    <>
      <motion.div
        id="scroll-indicator"
        style={{
          scaleX: scrollYProgress,
          position: "fixed",
          top: 0,
          left: 0,
          right: 0,
          height: "10px",
          originX: 0,
          backgroundColor: "#ff0088",
          zIndex: 9999,
          transformOrigin: "0% 50%",
        }}
      />
      <div style={{ minHeight: "200vh" }}>
        {" "}
        {/* 충분한 스크롤을 위한 임시 높이 */}
        <Toaster position="top-center" />
        <VideoBackground />
        <Header />
        <Hero />
        <FadeInSection>
          <About />
        </FadeInSection>
        <FadeInSection>
          <ServicesSection />
        </FadeInSection>
        <FadeInSection>
          <StatsSection />
        </FadeInSection>
        <ProjectGallery />
        <BlogSlider />
        <SimpleCounter />
        <SimpleTodo />
        <SimpleCalculator />
        <ThreeDPortfolio />
        <AvatarPortfolio />
        <ParticlePortfolio />
        <Contact />
      </div>
    </>
  );
}

export default App;

 

fade in, fade out 효과를 원하는 컴포넌트를 <FadeInSection> 태그로 감싸줍니다