gsap snap 기능 이해하기

Dustin Jung·2025년 2월 5일
1

GSAP

목록 보기
2/5

https://www.youtube.com/watch?v=bP7iGE3YKOU&list=PL4UVBBIc6giL8-6jvrClimg0cFL-Muqiq&index=4

https://webstoryboy.co.kr/1911

이 예제에서 3번 snap에 대한 이해를 하기 위해 하루를 씨름함.

<script>
/*
✅ GSAP ScrollTrigger + snap 기능 완벽 정리 ✅

✔ 각 섹션에 ScrollTrigger를 적용하고 순차적으로 고정
✔ snap 기능을 활용해 부드럽게 스크롤 이동
✔ 코드마다 설명 + 궁금했던 부분까지 주석으로 정리!
*/

// ① 모든 섹션(.parallax__item) 가져오기
let panels = gsap.utils.toArray(".parallax__item");

// ② 각 섹션의 ScrollTrigger 객체 저장 (snap 기능에서 활용 예정)
let tops = panels.map(panel => ScrollTrigger.create({
    trigger: panel, 
    start: "top top" // 각 섹션이 화면 최상단에 닿을 때 트리거됨
}));

/*
✅ tops 배열에는 각 섹션의 ScrollTrigger 객체가 저장됨
    tops = [
        { start: 값1, ... }, // section1
        { start: 값2, ... }, // section2
        { start: 값3, ... }, // section3
        ...
    ]

✔ ScrollTrigger.create() 실행 후 반환된 객체를 map()을 이용해 배열로 저장한 것!
✔ 이 값들은 snap 기능에서 활용할 예정 (현재까지는 사용 X)
*/

// ③ 각 섹션을 개별적으로 고정 (pin: true)
panels.forEach((panel, i) => {
    ScrollTrigger.create({
        trigger: panel,
        start: () => panel.offsetHeight < window.innerHeight ? "top top" : "bottom bottom", // 높이에 따라 다르게 설정
        pin: true, // 스크롤할 때 해당 섹션을 고정
        pinSpacing: false // 고정된 섹션이 다음 섹션과 겹쳐지지 않도록 함
    });
});

/*
✅ start 조건 설명
✔ 현재 브라우저의 viewport height (innerHeight)이 800px이라고 가정
✔ 만약 섹션 높이 (offsetHeight)가 1000px이면 → start: "bottom bottom" 적용
✔ 만약 섹션 높이가 600px이면 → start: "top top" 적용

*/

// ④ snap 기능 적용
ScrollTrigger.create({
    snap: {
        snapTo: (_, self) => {
            let panelStarts = tops.map(st => st.start); // tops 배열에서 start 값만 추출
            let snapScroll = gsap.utils.snap(panelStarts, self.scroll()); // 가장 가까운 값으로 스냅 적용
            return gsap.utils.normalize(0, ScrollTrigger.maxScroll(window), snapScroll); // 0~1 사이의 비율로 변환
        },
        duration: 0.5 // 스냅 애니메이션 지속 시간
    }
});

/*
✅ snap 기능 설명
✔ snapTo: (_, self) => { ... }
    → progress 값은 사용하지 않으므로 _로 무시 가능
    → self는 ScrollTrigger 자체를 가리킴 (this 사용 불가)

✔ let panelStarts = tops.map(st => st.start);
    → tops 배열에서 start 값만 추출 (예: ["top top", "top top", ...])
    → snap 기능에서 어느 위치로 이동할지 결정하는 기준이 됨

✔ let snapScroll = gsap.utils.snap(panelStarts, self.scroll());
    → 현재 스크롤 위치(self.scroll())에서 가장 가까운 panelStarts 값으로 스냅 적용

✔ return gsap.utils.normalize(0, ScrollTrigger.maxScroll(window), snapScroll);
    → 전체 스크롤 길이(0 ~ 최대 스크롤 값)를 0~1 사이의 값으로 변환
    → 퍼센트 단위로 변환해야 부드러운 스냅 효과 가능 (그렇지 않으면 딱딱하게 이동)
*/

</script>
profile
더스틴 정입니다

0개의 댓글