본문 바로가기
JavaScript

ZUM 기술 블로그 Fade in, Fade out 구현하기

by Vintz 2021. 10. 10.
반응형

IntersectionObserver API로 Fade in, Fade out 구현하기

ZUM 기술 블로그를 구경하다 디자인이 깔끔하고 이뻐서 클론해봤다. 정확히는 사이트의 Fade in, Fade out의 동작 방식이 궁금해서 직접 구현해봤다. 

Fade in, Fade out을 구현했다.


근데 이제 UI/UX를 곁들인..

기능 구현 외에도 깔끔한 UI/UX 덕분에 가독성도 좋았다. 뭔가 집중이 된달까..그래서 전체적인 분위기나 모바일 대응도 구현했다.


동작 방식 알아보기

  • 해당 블로그는 첫화면에 노출되는 포스트는 shown 클래스를 생성해서 바로 보여주게 된다.
    • ➡️ 동적으로 클래스를 만듦
  • 그 후 포스트들은 스크롤 다운 시 animate 클래스를 생성해서 보여주게 된다.
    • ➡️ moveUp 애니메이션 작동, 포스트가 올라옴
    • ➡️ 각각 다른 animation-duration이 적용된다. 랜덤임
  1. 모든 포스트는 초기값에 opacity: 0이 적용되어 있다.
  2. 화면의 크기에 따라 첫화면에 노출된 포스트는 shown 클래스 생성
  3. 첫화면에 노출되지 않은 포스트들은 스크롤 다운 시 animate 클래스 생성
  4. animate 클래스가 추가된 포스트는 moveUp 애니메이션 작동

여기까지 알아낸 내용을 토대로 기능을 구현했다.


문제 해결하기

클래스가 동적으로 생성되기 때문에 스크롤을 다운한 상태에서 새로고침 시, 그 상태에서 첫화면이 뜨기 때문에 해당 위치의(노출된) 포스트를 바로 보여주고 다른 포스트들은 애니메이션이 구현되어야 한다. 이 부분에 시간을 많이 쓰게 되었다.

const article = document.querySelectorAll('.content');
let className = 'show';

const observerCallback = (entries, observer) => {
  entries.forEach(({ isIntersecting, intersectionRatio, target }) => {
    if (isIntersecting && intersectionRatio > 0) {
      // 처음에 노출된 포스트들은 className이 show
      target.classList.add(className);
      observer.unobserve(target);
    }
  });
  // 그 후 className은 animate
  className = 'animate';
};

const observerOptions = {
  root: null,
  rootMargin: '0px',
  threshold: 0.3,
};

const io = new IntersectionObserver(observerCallback, observerOptions);
articles.forEach((article) => io.observe(article));

구현해놓고 보니 간단해 보이지만 구현하기 전엔 굉장히 막막했다. 코드가 엄청 길어지기도 했었고 동작이 제대로 되지 않아서 고생도 했지만 결과는 만족스러웠다.

 

이것저것 시도해보다가 결국 컴퓨터가 원하는 답을 얻게 되어서 기분이 좋다. 😁

 

그리고 또 하나 재미있었던 부분이 각기 다른 animation-duration 시간이었다. 포스트가 올라올 때마다 올라오는 시간이 모두 달랐는데 이것도 꼭 구현해보고 싶었다. 그러다 떠오른게 예전 유튜브에서 CSS로 구현한 커피의 수증기 표현이었다. 다행히 저장해놓은 것이 있어서 적용했는데 역시..! 나름 만족스러운 결과가 나왔다.

const randomNum = Math.floor(Math.random() * 7 + 5);
const article = document.createElement('article');
article.setAttribute('class', 'content');
article.setAttribute('style', `--i:${randomNum}`);

.content.animate {
  animation: moveUp 0.65s;
  animation-duration: calc(var(--i) * 0.07s);
  opacity: 1;
}

신경쓴 부분들

  • 모바일 반응(flex layout)
  • 동적으로 생성되는 클래스
    • 동적으로 클래스가 생성되기 때문에 첫화면이 위에 있든 아래에 있든(아래에서 새로고침 시) 애니메이션이 구현된다.
  • 각기 다른 animation-duration 시간
  • 부드러운 애니메이션
  • 최대한 간결한 태그 깊이
    • 부스트코스에서 웹 UI를 배울 때 지적을 많이 받은 부분이 '불필요한 태그를 생성하지 말라'는 것이었다. 깊이가 깊을수록 유지보수가 어렵고 성능상 좋지 않다는 이유였다.
    • 그래서 최대한 간결한 뎁스를 유지하도록 노력했다.
  • 전체 코드 보기
반응형