웹 개발을 하면서 조금 있어 보이는(?) 애니메이션을 손에 꼽자면 바로 스크롤을 기반으로 하는 애니메이션이다. 스크를을 기반으로 하는 애니메이션을 만들려면 다음과 같이 작성해야한다.
window.addEventListener('scroll', () => {
// do something
})
위와 같이 해당하는 스크롤을 작성을 하면 된다. 하지만 위의 방법대로 만들게 되면 불편하거나 리소스를 낭비를 할 수 있다. 그 이유는 다음과 같다.
이와 같은 문제떄문에 외부의 라이브러리를 가져와서 편하게 사용하거나, 직접 복잡한 로직을 통해 만들게 된다. 하지만 이러한 방법은 라이브러리를 가져오거나, 복잡한 로직을 통해 만들게 되면서 코드의 가독성이 떨어지게 된다.
그렇다면 이러한 문제를 어떻게 해결할 수 있을까? 그것이 바로 IntersectionObserver
이다.
IntersectionObserver
는 브라우저에서 지원하는 api로, 해당하는 요소가 뷰포인트안에 들어와있는지 확인을 할 수 있다. 게다가 IntersectionObserver
는 뷰포인트에 들어와있는지 확인을 할 때, 해당하는 요소의 크기를 기반으로 확인을 하기 때문에 브라우저에 따라서 미묘하게 원하는 방식으로 작동되지 않는다는 문제를 해결할 수 있다.
게다가 사용방법도 꽤 간단하다. 다음과 같이 사용하면 된다.
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('active')
// do something
} else{
entry.target.classList.remove('active')
// do something
}
})
})
observer.observe(document.querySelector('.target'))
위와 같이 사용될 수 있다. IntersectionObserver
는 생성자를 통해 생성을 하며, 생성자의 인자로는 콜백함수를 받는다. 콜백함수의 인자로는 entries
가 들어오게 되는데, 이는 IntersectionObserverEntry
의 배열이다.
entries
의 인자는 여러개가 있는 데 그 중 하나는 isIntersecting
인데, 해당하는 요소가 뷰포인트안에 들어와있는지 확인을 할 수 있다. isIntersecting
이 true
이면 해당하는 요소가 뷰포인트안에 들어와있는 것이고, false
이면 해당하는 요소가 뷰포인트안에 들어와있지 않은 것이다.
게다가 해당하는 요소도 확인을 할 수 있는데, target
이라는 속성을 통해 확인을 할 수 있다. 이렇게만 사용해도 충분히 좋지만 만약 원한다면 더 많은 옵션들도 사용할 수 있다.
IntersectionObserver
는 생성자의 두번째 인자로 옵션을 받을 수 있다. 이 옵션들은 다음과 같다.
isIntersecting
이 true
가 되는지 지정할 수 있다. 기본값은 0이다.위의 옵션들을 사용한다면, 더 세밀한 부분을 조정하여 조금은 더 복합적으로 사용할 수 있다.
위의 옵션들을 사용하여, 더 복합적으로 사용해보자. 다음과 같이 사용하면 된다.
const opt = {
root: document.querySelector('.container'),
rootMargin: '0px 0px -100px 0px',
threshold: 0.5
}
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('active')
// do something
} else{
entry.target.classList.remove('active')
// do something
}
})
}, opt)
위의 코드에서는 root
를 .container
로 지정하였다. 이는 .container
안에 있는 요소들이 뷰포인트안에 들어와있는지 확인을 하겠다는 의미이다.
또한 rootMargin
을 0px 0px -100px 0px
로 지정하였다. 이는 .container
의 아래쪽으로 100px의 여백을 준 것이다. 이렇게 하면 .container
의 아래쪽으로 100px의 여백이 생기게 되고, 그 여백안에 들어와있는 요소들이 뷰포인트안에 들어와있는지 확인을 할 수 있게 된다.
그리고 threshold
를 0.5
로 지정하여, .container
의 아래쪽으로 100px의 여백안에 들어와있는 요소들이 뷰포인트안에 50%가 들어와있는지 확인을 하겠다는 의미이다.
위의 모든 조건들을 만족하데 된다면 isIntersecting
이 true
가 되고, 그렇지 않다면 false
가 된다. 그렇게 된다면 클래스를 이용해 조작하거나 별도의 로직을 적용시켜주거나 외부 라이브러리를 사용하여 애니메이션을 넣어주면 된다.
나 같은 경우에는 다음과 같이 IntersectionObserve
api를 사용하여 무한 스크롤을 구현하였다.
function infiniteScrollHandel() {
const infiniteScroll = document.querySelector(".infinite-scroll");
const options = {
rootMargin: "300px 0px 0px 0px",
threshold: 0,
};
const observer = new IntersectionObserver(async (entries) => {
if (entry.isIntersecting) {
if (searchValue) {
renderMovies()
} else if (movieListEl.classList.contains("movie-list__error")) {
}
}
}, options);
observer.observe(infiniteScroll);
}
infinite-scroll이라는 클래스를 가진 요소가 뷰포인트에 들어오면, renderMovies()
를 실행시켜 무한정으로 영화를 불러오게 만들었다. 이렇게 무궁무진하게 활용하여 사용할 수 있다.
이렇게 간단하게 IntersectionObserver
를 사용하여 다양한 예시를 살펴보았다. 스크롤을 기반으로 하는 이벤트는 구현하기에도 복잡하기도 하고 리소스 및 성능에도 적지않은 영향을 줄 수도 있기 때문에, IntersectionObserver
를 사용하여 스크롤을 기반으로 하는 이벤트를 구현하면 좋을 것 같다.
어때요 스크롤 기반 애니메이션 만들기 정말 쉽죠?