개발자일기/Tutorial

화면에 나타나면 애니메이션이 작동되게 하라!(CSS, VanilaJS)

뫙뭉 2022. 1. 24. 23:17
반응형

이전 포스트에서 열심히 '한글자씩 나타나는 애니메이션'에 대해 만들었다.

그런데 문제가 하나 있다.

해당 요소는 저~~~기 밑에 있는데 사이트가 렌더링이 되자마자 애니메이션이 발동된다면 여태 힘들게 애니메이션을 만든 의미가 없지 않은가!! 요소가 화면 안에 들어왔을 때 애니메이션이 발동되어야 된다 이말이다. 그래야 내가 열심히 만든 애니메이션을 자랑할 수가 있다.

 

그렇기 때문에 오늘은!! 요소가 화면에 보일 때 애니메이션이 작동하도록 하는 방법에 대해 블로깅하려 한다.

 

화면의 위치와 요소의 위치

우선 화면의 상단의 위치를 알아야겠지. 이것은 간단하다.

window.pageYoffset;
window.scrollY;

방법은 위의 두가지가 있는데 둘의 차이가 무엇이냐.

window.scrollY 는 구형 브라우저에서 작동이 안된다. 그렇기에 MDN에서는 브라우저 환경을 감안하여 window.pageYoffset을 사용하기를 권장한다. 하지만 나는 scrollY가 더 이해하기 쉽기에 scrollY를 사용하겠다.

정확한 의미는 '페이지가 얼마나 스크롤 되었는지의 값을 리턴한다' 정도 되겠다.

 

화면의 위치를 구하는 법은 알아보았고 이제 요소의 위치를 알아내어 보자.

요소의 위치값을 얻기 위해서는 getBoundingClientRect()를 사용하면 된다.

 

그렇다면 getBoundingClientRect라는 이 이름긴 메소드는 무엇을 반환하는가.

콘솔 로그를 한번 찍어보자

아주 다양한 값을 갖고 있군요!

다음은 어떤 element의 getBoundingClientRect를 찍어본 것. element.getBoundingClientRect()를 찍어보면 된다.

bottom, left, right, top과 같이 위치에 관련된 값을 리턴한다.

여기서 중요한 것!!

이 값들은 viewport를 기준으로 나온 값이라는 것! 

그것이 무슨말인지 그림으로 설명해보겠다.

 

그림의 색감이 영 마음에 들지 않는다

그림에서 보면 window.scrollY + element.getBoundingClientRect().top 이 소위말하는 element의 절대좌표가 되겠다.

우리가 바라는 것은 이 절대좌표를 이용하여  화면에 요소가 나타났을 때 애니메이션이 발동해야 된다는 것.

위에서 설명한 것들을 토대로 우리는 전략을 세워야 한다.

 

구한 위치의 좌표를 통해 작전을 짜보자

애니메이션이 발동되는 클래스명 추가하기

우선 CSS부터 생각해보자

특정 조건에 나타나는 애니메이션을 표현할 때 내가 자주 쓰는 방법은

조건이 만족되면 클래스명을 추가하는 것.

우선 클래스 'on'을 간단하게 추가해보자.

// index.js

const content = document.querySelector('.content');

function animationWhendisplayed(){
  content.classList.add('on');
}

animationWhendisplayed();
/* style.css */

.content{
  width: 100%;
  height: 500px;
  opacity: 0;
  transition: opacity 1000ms ease-in;
}

.content.on{
  opacity: 1;
}

이렇게 해 놓으면 content에 on 클래스가 추가되면 opacity가 1이 되면서 짠~~ 하고 나타나게 된다.

갑자기 나타나는 것이 아니라면 transition도 잊지 말고 추가해 주길 바란다.

어쨌든 on이 추가되는 시점만 잘 조절한다면 어떤 조건이든 간단하게 애니메이션 상태를 조절할 수 있게 되는 것.

 

어느 시점에 클래스명을 추가해야 할까?

그렇다면 on이 추가되는 시점은 정확히 언제가 될 것인가?

그건 바로 viewport의 가장 아랫부분이 content의 가장 윗부분과 닿는 그 순간이 화면에 보이는 순간일 것이다!

바로 viewport의 bottom 좌표 > content의 top 좌표 가 우리가 원하는 조건이 된다.

지금 이 순간!

그림에서 보면

viewport의 가장 아랫부분은 window.scrollY + window.innerHeight,

content의 가장 윗부분은  window.scrollY + content.getBoundingClientRect().top 가 된다.

window.scrollY + window.innerHeight > window.scrollY + content.getBoundingClientRect().top 이 조건이 되지만

자세히 두 식을 비교해보면 window.scrollY가 중복되지 않는가?

그렇다. 결국 위에서 구구절절 절대좌표에 대해서 설명하였지만

중학교 때 배웠던 부등식의 이항을 이용하여 중복되는 부분을 없애주면...

window.innerHeight > content.getBoundingClientRect().top 이 되는 순간이 결국 우리가 바라는 순간이다.

 

함수에 조건을 추가하자!

이후의 문제는 간단하다. 위의 함수에 조건을 추가하기만 하면 되는 것.

const content = document.querySelector('.content');

function animationWhendisplayed(){
  if(window.innerHeight > content.getBoundingClientRect().top){
    content.classList.add('on');
  }
}

animationWhendisplayed();

하지만 이렇게 끝내버리면 처음 사이트가 불러와졌을 때만 함수가 실행 되기 때문에 아무 일도 일어나지 않는다.

사이트가 로드된 순간에는 해당 조건이 만족되어 있지 않기 때문.

우리는 매순간 스크롤이 될 때마다 위치를 체크해야 하기 때문에 이벤트 리스너를 등록하면 된다.

 

const content = document.querySelector('.content');

function animationWhendisplayed(){
  window.addEventListner('scroll', () => {
    if(window.innerHeight > content.getBoundingClientRect().top){
      content.classList.add('on');
    }
  }
}

animationWhendisplayed();

이리하여 스크롤이 될 때 마다 요소의 위치를 체크하여 viewport안에 들어왔을 때 애니메이션이 발동되는 기능이 완성되었다.

만약에 화면에 나타나자마자 발동되는 것이 싫다면 window.innerHeight에 적절한 값을 연산해주면 된다.

예를 들어 화면에 절반정도 위치에서 발동시키고 싶다 하면 window.innerHeight * 0.5를 해주면 되겠다.

 

마무으리..

코드의 길이도 짧고 간단해 보이지만 화면과 요소의 좌표에 대한 이해가 없으면 짤 수 없는 코드이기에 기본이 중요하다는 것을 다시 알게 해주는 기능 구현이지 않나 생각해본다.

참고로 나는 포트폴리오에 위의 기능을 사용해서 글자가 샤랄라~~ 나타나는 기능을 추가했다.

이렇게 평소에 연습했던 기능들을 조합하면 더 멋있는 사이트를 만들어 낼 수 있다는 사실!!

모두들 열심히 연습해서 나만의 멋있는 사이트를 만들 수 있길 바란다.

반응형