문제 상황
스크롤 애니메이션이 들어간 페이지를 만들다 보면 데스크톱에서는 잘 보이지만, 모바일에서는 오히려 불편한 경우가 있습니다.
예를 들어 가로로 이동하는 GSAP 애니메이션을 큰 화면에서만 실행하고, 화면 너비가 1080px 이하일 때는 실행하지 않게 만들고 싶을 수 있습니다.
이럴 때는 현재 화면 크기를 확인한 뒤 조건에 맞을 때만 함수를 실행하면 됩니다.
기존 코드
처음에는 화면 크기와 관계없이 애니메이션을 바로 등록했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
useEffect(() => {
const projectList = document.getElementById("projectList");
gsap.to(".projectsBox", {
xPercent: -100,
scrollTrigger: {
trigger: ".projectsBox",
start: `${projectList.clientHeight + 150}px 99%`,
end: `100%-=${projectList.clientHeight}px 10%`,
scrub: 0.5,
},
});
}, []);
이렇게 하면 모바일 화면에서도 애니메이션이 등록됩니다.
화면이 좁은 환경에서는 레이아웃이 깨지거나 불필요한 스크롤 동작이 생길 수 있습니다.
화면 너비 조건 추가하기
window.innerWidth를 확인해서 특정 너비 이상일 때만 실행할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
useEffect(() => {
const setupAnimation = () => {
if (window.innerWidth <= 1080) return;
const projectList = document.getElementById("projectList");
if (!projectList) return;
gsap.to(".projectsBox", {
xPercent: -100,
scrollTrigger: {
trigger: ".projectsBox",
start: `${projectList.clientHeight + 150}px 99%`,
end: `100%-=${projectList.clientHeight}px 10%`,
scrub: 0.5,
},
});
};
setupAnimation();
}, []);
이제 화면 너비가 1080px 이하라면 애니메이션 등록을 건너뜁니다.
resize 이벤트까지 처리하기
사용자가 브라우저 크기를 변경할 수도 있으므로 resize 이벤트를 함께 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
useEffect(() => {
const setupAnimation = () => {
if (window.innerWidth <= 1080) return;
const projectList = document.getElementById("projectList");
if (!projectList) return;
gsap.to(".projectsBox", {
xPercent: -100,
scrollTrigger: {
trigger: ".projectsBox",
start: `${projectList.clientHeight + 150}px 99%`,
end: `100%-=${projectList.clientHeight}px 10%`,
scrub: 0.5,
},
});
};
setupAnimation();
window.addEventListener("resize", setupAnimation);
return () => {
window.removeEventListener("resize", setupAnimation);
};
}, []);
cleanup에서 이벤트를 제거해주면 컴포넌트가 사라진 뒤에도 이벤트가 남아 있는 문제를 막을 수 있습니다.
GSAP에서는 cleanup도 중요해요
GSAP ScrollTrigger를 사용하는 경우에는 애니메이션이 중복 등록되지 않도록 정리 로직도 고려해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
useEffect(() => {
let animation: gsap.core.Tween | null = null;
const setupAnimation = () => {
animation?.kill();
if (window.innerWidth <= 1080) return;
const projectList = document.getElementById("projectList");
if (!projectList) return;
animation = gsap.to(".projectsBox", {
xPercent: -100,
scrollTrigger: {
trigger: ".projectsBox",
start: `${projectList.clientHeight + 150}px 99%`,
end: `100%-=${projectList.clientHeight}px 10%`,
scrub: 0.5,
},
});
};
setupAnimation();
window.addEventListener("resize", setupAnimation);
return () => {
animation?.kill();
window.removeEventListener("resize", setupAnimation);
};
}, []);
화면 크기가 바뀔 때마다 애니메이션을 새로 등록한다면 이전 애니메이션을 정리하는 것이 안전합니다.
마무리
화면 크기에 따라 특정 함수를 실행할지 결정하려면 window.innerWidth를 조건으로 사용할 수 있습니다.
처음 렌더링 시 한 번 실행하고, 화면 크기 변경까지 대응해야 한다면 resize 이벤트를 함께 등록하면 됩니다.
이벤트 리스너와 애니메이션 인스턴스는 cleanup에서 정리해두는 것이 좋습니다.