애플의 웹 사이트는 멋지다. 사이트에 특별한 기능이 있는건 아니다. 대부분 제품 소개 페이지다. 제품 소개페이지를 얼마나 잘 만들었길래, 뭐가 멋지다는걸까? 의문이 들 법하다. 그런데, 하나하나 살펴보면, 정말 세심하게 공들인 느낌이다. 단순한 웹 페이지일 뿐이지만, 사용자에게 제품의 특징을 잘 전달하기 위해 여러가지 효과를 만들어냈다.스크롤에 따라 이미지가 fade-in/fade-out
되는건 기본이고, 확대되거나 옆에서 나타나기도한다. 영상이 재생되는가 하면, 그래프가 그려진다. 이 모든것들은 오로지 스크롤
이라는 이벤트를 기반으로 만들어졌다. 사용자가 스크롤만 할 뿐이지만, 웹 페이지에서는 마치 한편의 영상이 재생되는것처럼 보인다.
모던 웹에서 다양한 효과는 많은 부분 스크롤로 표현할 수 있다. 가장 간단하게 opacity
와 transform
만 사용하더라도 웹사이트를 충분히 interactive
하게 만들수 있다. 어떤 목록을 아래로 스크롤하다 viewport에 나타나는 순간 위로 올라오는 애니메이션과 함께 점점 밝아지도록 할 수 있다. 이 단순한 효과만으로 무미건조하고 딱딱한 목록에 생명을 불어 넣을 수 있다.
opacity와 transform을 이용해서 목록을 interactive하게 만들기
결과물부터 확인하자. 스크롤을 아래로 내리면 각 article과 image가 아래에서 위로 자연스럽게 나타난다.
See the Pen list item show on scroll by Hyunwoo Seo (@blueshw) on CodePen.
자바스크립트 코드는 다음과 같다.
function isElementUnderBottom(elem, triggerDiff) {
const { top } = elem.getBoundingClientRect();
const { innerHeight } = window;
return top > innerHeight + (triggerDiff || 0);
}
function handleScroll() {
const elems = document.querySelectorAll('.up-on-scroll');
elems.forEach(elem => {
if (isElementUnderBottom(elem, -20)) {
elem.style.opacity = "0";
elem.style.transform = 'translateY(70px)';
} else {
elem.style.opacity = "1";
elem.style.transform = 'translateY(0px)';
}
})
}
window.addEventListener('scroll', handleScroll);
무척 간단하다. isElementUnderBottom
는 함수 이름에서도 알 수 있듯이 element가 스크린 아래쪽에 있는지를 검사한다. 스크린 아래에 있으면 true를 반환할것이고, 스크린보다 위에 있으면 false를 반환한다. IntersectionObserver
를 사용할 수도 있지만, 스크린 아래쪽에 있는지 여부만 판단하기 때문에 getBoundingClientRect
메서드를 이용해서 비교하는게 훨씬 간편하다.
handleScroll
은 scroll 이벤트의 핸들러 함수다. 스크롤이 발생하면 이 함수가 실행된다. querySelectorAll
API를 이용해서 class 이름을 가진 element를 모두 가져오자. 가져온 각 element가 화면보다 아래에 있다면 opacity: 0
, transform: translateY(70px)
스타일이 적용되도록 하고, 화면 안에 있다면 opacity: 1
, transform: translateY(0px)
스타일이 적용되도록 한다. 이제 스크롤을 하면 아래에서 element가 보일때 즈음 미리 설정한 transition
속성을 통해 element가 아래에서 부드럽게 나타나는것을 확인할 수 있다. 좀더 정교하게 구현하려면 requestAnimationFrame
API를 이용해서 초당 60회 실행되도록 만들어야겠지만, 지금 만드는 효과는 굳이 초당 60회나 실행될 필요는 없다. 좀더 부드러운 움직임을 만들고 싶다면, 반드시 이 API를 사용해서 구현하자.
다음은 HTML과 CSS 코드를 살펴보자.
<style>
.list .up-on-scroll {
...
transition: transform 0.7s, opacity 1s;
}
</style>
<div class="list">
...
<article class="up-on-scroll">
We are dancing. We are extra dancing...
</article>
<article class="up-on-scroll">
We are extra cool everyday dancing...
</article>
<div class="img-wrap">
<img src="..." alt="img1" class="up-on-scroll" />
</div>
...
</div>
아래에서 위로 올라오는 효과를 주고 싶은 element에 up-on-scroll
을 붙여준다. 그리고 transition
속성에 opacity와 transform를 적용한다. 끝났다.
더욱 화려한 스크롤 이벤트를 만들어보자
결과물부터 확인하자.
See the Pen more interactive effect on scroll by Hyunwoo Seo (@blueshw) on CodePen.
세가지 정도 효과를 만들어봤다(코드 정리가 안되있어 codepen에서 직접 확인하자).
- 이미지가 하나씩 아래에서 올라오면서 가운데에서 멈춘다. 기존 이미지는 새로운 이미지로 교체된다 .
- 스크롤함에 따라 좌측 설명 부분과 우측의 이미지가 서로 다른 속도로 움직인다.
- 화면에 가득찬 이미지가 있고, 스크롤함에 따라 점점 투명해져 배경색을 교체한다(black => white).
주로 사용한 css 속성은 다음과 같다.
- 이미지 wrapping 태그에
position: sticky
속성을 주었다. sticky 속성은 viewport에 고정하는 fixed와는 다르게 scroll box에 고정한다. 즉, 부모 element가 스크롤이 가능하다면 부모 element가 스크롤되는 동안 position을 유지한다.- 우측 이미지에
transform
으로 스크롤 위치를 조절했다. 좀더 부드러운 스크롤 동작을 위해requestAnimationFrame
API를 사용하여throttle
처리했다.- sticky와
filter: grayscale()
,opacity
를 사용했다.
결론
스크롤 이벤트만 잘 활용해도 딱딱한 웹 페이지에 생명을 불어넣을 수 있다. 크게 어려운 개념도 없기 때문에 아이이디만 있으면 누구나 아름다운 웹 페이지 제작이 가능하다. 그렇다고 filter 등 연산량이 많은 작업을 너무 과하게 사용하면 성능 저하가 발생할 수 있으니 조심히 사용하자. 게다가 오래된 브라우저를 지원해야하는 경우라면 더더욱 조심히 사용해야한다.