들어가며
현재 작업하는 프로젝트에서 전체 페이지 스크롤 시 현재 위치 값을 보여주는 페이지 내비게이션, 특정 콘텐츠가 화면에서 노출됐을 때 좌우 스크롤이 가능한 가이드 역할을 하는 UI가 있었는데요. 이렇게 화면 스크롤 인터랙션이 필요할 때 사용하는 Scroll Magic 라이브러리를 사용하게 되었습니다. 희원 주임님이 작성한 ScrollMagic Plugin & TweenMax 내용을 이어 자주 쓰이는 UI를 정리하고자 합니다.
ScrollMaic Browser Support
Firefox 26+, Chrome 30+, Safari 5.1+, Opera 10+, IE 9+
ScrollMagic의 동작 원리 (희원 주임님 블로그에서 내용을 가져왔어요)
- ScrollMagic 컨트롤러 생성
- 애니메이션 생성
- Scene 오브젝트 생성
- 애니메이션을 Scene 오브젝트에 추가
- Scene 오브젝트를 ScrollMagic 컨트롤러에 추가
1. Page Indicatior
한 페이지에서 어느 영역 콘텐츠에 위치하는지 보여주는 기능
- ScrollMagic 컨트롤러 생성
- 콘텐츠별 높이 값 설정
- 콘텐츠 높이와 뷰포트 화면의 비율의 최솟값 설정
- 페이지 인디게이터의 활성화 클래스 추가
const controller = new ScrollMagic.Controller({ loglevel: 3 }); // 1. ScrollMagic 컨트롤러 생성 const section = document.querySelectorAll('.section'); const ratio, elHeight = []; // 2. 콘텐츠 높이값, 화면 비율 설정 section.forEach((el, index) => { const height = el.clientHeight; const num = Number((height / window.innerHeight).toFixed(2)); elHeight.push(height); ratio.push(num); }); // 3. 최솟값 결정 let min = ratio.reduce((prev, curr) => { return prev > curr ? curr : prev; }); section.forEach((el, index) => { const id = el.getAttribute('id'); new ScrollMagic.Scene({ triggerElement: `#${id}`, duration: elHeight[index], triggerHook: 1 - min, loglevel: 3, }) .setClassToggle(`.page_navigation span:nth-child(${index + 1})`, 'active') // 4. 페이지 인디게이터의 활성화 클래스 추가 .addIndicators() // debug용 코드 .addTo(controller); });
2. Page Navigation
위에 설명한 페이지 인디게이터와 유사하지만 버튼 요소를 넣어 클릭 시 콘텐츠의 위치로 상단 이동시켜주는 기능이 필요할 때는 triggerHook 값을 0으로 설정해줘야 합니다.
- ScrollMagic 컨트롤러 생성
- 콘텐츠별 높이 값 설정
- 뷰포트 지점(0, onLeave) 설정
- trigger 이벤트를 콘텐츠의 최상단으로 위치
- 페이지 네비게이션의 활성화 클래스 추가
- controller의 scrollTo 이벤트에 따른 부드럽게 이동하는 애니메이션 효과 추가
- 내비게이션 클릭 시 해당 href값으로 scrollTo 이벤트 발생
const controller = new ScrollMagic.Controller(); // 1. ScrollMagic 컨트롤러 생성
const section = document.querySelectorAll('.section');
section.forEach((el, index) => {
const id = el.getAttribute('id');
const height = el.clientHeight; // 2. 콘텐츠별 높이 값 설정
new ScrollMagic.Scene({ triggerElement: `#${id}`, duration: height, triggerHook: 0 }) // 3. 뷰포트 지점(0, OnLeave) 설정
.setClassToggle(`nav a:nth-child(${index + 1})`, 'active') // 4. 페이지 내비게이션의 활성화 클래스 추가
.addIndicators()
.addTo(controller);
});
// 5. controller의 scrollTo 이벤트에 따른 부드럽게 이동하는 TweenMax 효과 추가
controller.scrollTo(function (newpos) {
TweenMax.to(window, 0.5, { scrollTo: { y: newpos } });
});
const nav = document.querySelectorAll('nav a');
nav.forEach((el) => {
// 6. 내비게이션 클릭 시 해당 href 값에 따른 scrollTo 이벤트 발생
el.addEventListener('click', (e) => {
const id = e.target.getAttribute('href');
if (document.querySelector(id)) {
e.preventDefault();
controller.scrollTo(id);
}
});
});
3. Parallax Scroll
패럴럭스 효과는 PC 사이트 작업 시 마이크로 사이트나 브랜드 프로모션 사이트에서 디자인적 요소로 임팩트를 주기 위하여 사용됩니다. 마우스 스크롤에 따라 원거리에 있는 배경 이미지는 느리게 움직이게 하고, 근거리에 있는 사물 이미지는 빠르게 움직이도록 함으로써 입체감을 느끼게 합니다. 혹시 패럴럭스 스크롤이 어떤 것인지 잘 모르시는 분은 애플 에어팟 프로 사이트를 확인해주세요.
애플 에어팟 사이트 구경하기
- 너비, 높이 100%의 풀 페이지 컨테이너 생성(css)
- ScrollMagic 컨트롤러 생성
- 움직일 요소와 인터랙션 추가
- 콘텐츠 setPin으로 고정
const controller = new ScrollMagic.Controller(); // 2. ScrollMagic 컨트롤러 생성
const section = document.querySelectorAll('.section');
let timeLineMax = new TimelineMax();
// 3. 움직일 요소와 인터랙션 추가
section.forEach((el, boxIndex) => {
if (boxIndex > 0) {
timeLineMax.fromTo(
`#${el.id}`,
1,
{ y: '-100%' },
{ y: '0%', ease: Linear.easeNone },
);
}
});
new ScrollMagic.Scene({
triggerElement: '#pinContainer',
triggerHook: 'onLeave',
duration: '300%',
})
.setPin('#pinContainer') // 4. 콘텐츠 setPin으로 고정
.setTween(timeLineMax)
.addIndicators()
.addTo(controller);
4. Reveal on Scroll
회사 홈페이지를 스크롤 하면 콘텐츠가 뷰포트에 도달했을 경우 순차적으로 보이는 UI를 사용하고 있습니다. 인터랙션도 크지 않아 동적으로 보이는 요소에 단조롭게 speed와 delay를 계산하여 작성했습니다. Scroll Magic을 사용하면 더 다양한 인터랙션을 만들 수 있습니다. 스크롤 방향에 따라 콘텐츠를 다시 보여주거나, 각 콘텐츠 노출 속도를 다르게 설정할 수 있습니다.
- ScrollMagic 컨트롤러 생성
- 뷰포트 지점 설정
- 콘텐츠 인터랙션 추가
- 콘텐츠 활성화 클래스 추가
const controller = new ScrollMagic.Controller({ globalSceneOptions: { offset: 200 } }); // // 1. ScrollMagic 컨트롤러 생성
const section = document.querySelectorAll('.section');
section.forEach((el, boxIndex) => {
let tween;
const boxes = el.querySelectorAll('.box');
boxes.forEach((item, itemIndex) => {
const scene = new ScrollMagic.Scene({
triggerElement: item,
triggerHook: 0.9, // 2. 뷰포트 지점 설정
// reverse: false // 스크롤을 위로 올렸을 경우 인터랙션 재생 여부
});
if (el.dataset.speed) {
// 3. 콘텐츠 인터랙션 추가(TweenMax 이용)
tween = TweenMax.to(item, el.dataset.speed, {
opacity: 0.5,
ease: el.dataset.ease,
}).duration(el.dataset.speed);
}
scene
.setClassToggle(item, 'visible') // 4. 콘텐츠 활성화 클래스 추가
.setTween(tween)
.addTo(controller);
});
});
마치며
지난번 스크롤 매직 관련 포스팅을 읽었는데도 막상 필요할 때 라이브러리 자체를 잊어버렸더라고요 :) 읽고 계신 여러분들은 스크롤 이벤트 관련 인터랙션 작업이 필요하실 때 참고해서 사용하시길 바랍니다.
감사합니다.
참고문서