본문 바로가기
WEB Basic/JavaScript

[JavaScript] 스크롤 시 나타나는 효과 구현하기: Intersection Observer API

by Devinus 2024. 1. 16.

1. 구현 결과 미리보기

Fade In 효과와 Intersection Observer

첫 번째 섹션

img

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Officiis rem voluptatem deleniti quae, nisi quas minus sint explicabo? Similique quae minus consequuntur sint, commodi placeat hic ullam necessitatibus optio alias?

두 번째 섹션

img

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Facere optio iure labore quo cum excepturi fugit, eum ad velit! Placeat velit a officiis architecto perspiciatis possimus aspernatur nostrum veritatis maiores?

세 번째 섹션

img

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Impedit porro atque officiis explicabo dolores error ullam. Ea quidem voluptate, ullam odit rem error, maxime voluptas hic, voluptatem nesciunt eum in!

네 번째 섹션

img

Lorem ipsum dolor sit amet consectetur adipisicing elit. Modi minus doloremque, nam deleniti fugit vel totam dolorum placeat architecto consectetur quia incidunt. Nam, iusto quisquam in vero cum assumenda rerum?

2. 분석

1. 동작 원리: 화면 스크롤 시 요소의 교차 영역을 감지하고, 이벤트를 통해 페이드 인 효과를 부여합니다.

2. 주요 기능:

  • 비동기적 감지: 브라우저 성능에 부담을 주지 않으면서 화면에 보이는 요소의 상태를 확인합니다.
  • 이벤트 기반 실행: 스크롤 시 교차 영역의 변화를 감지하여 콜백 함수를 실행하여 페이드 인 효과를 적용합니다. 이벤트 리스너를 사용자가 `addEventListener`함수로 직접 추가하는 개념이 아니라, `IntersectionObserver API`에 관찰 대상으로 등록된 요소들에 스크롤 이벤트가 추가 됩니다.

활용 예시로 화면에 표시되는 각 섹션에 Fade In 효과를 부여하기 위해 Intersection Observer를 사용했습니다. 

아래와 같이 작성된 코드는 `querySelectorAll`함수를 활용해서 `.fade-wrap`클래스를 갖는 모든 요소를 관찰하기 때문에 각 요소에 모두 이벤트가 적용 됩니다.

  /* javascript */
  // Intersection Observer 생성
  const observer = new IntersectionObserver(
    (entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // 화면에 들어옴
          entry.target.classList.add("fade-in");
        } else {
          // 화면에서 나감
          entry.target.classList.remove("fade-in");
        }
      });
    },
    // 화면에서 해당 요소가 10% 이상 보일 경우 화면에 들어온 것으로 판단함
    { threshold: 0.1 }
  );

  // 관찰 대상 설정
  const targetElements = document.querySelectorAll(".fade-wrap");
  targetElements.forEach((element) => {
    observer.observe(element);
  });

 

각 섹션은 `.fade-wrap` 클래스를 가지고 있으며, 화면에 들어올 때 해당 클래스에 `.fade-in` 클래스가 추가되어 투명도가 0에서 1로 변하면서 나타나게 됩니다. 

/* style */
.fade-wrap {
    /* 나타나는 효과가 1초동안 발생 */
    transition: 1s;

    /* 투명도 0 (안보임) */
    opacity: 0;

    /* 왼쪽에서 오른쪽으로 나타나게 하기 위함 */
    position: relative;
    left: -50px;

    margin-bottom: 20px;
}
.fade-wrap.fade-in {
    /* 투명도 0 (보임) */
    opacity: 1;

    /* 왼쪽에서 오른쪽으로 나타나게 하기 위함 */
    left: 0;
}

 

위와 같이 Intersection Observer를 사용하여 스크롤 시 Fade In 효과를 부여함으로써 UI 성능을 향상시킬 수 있습니다. 필요한 요소에만 효과를 적용하여 효율적인 관리가 가능합니다.</span >

3. 구현

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Fade In 효과와 Intersection Observer</title>
    <style>
      .pv-box {
        border: 1px solid black;
        padding: 10px;

        height: 500px;
        overflow-y: scroll;
      }
      .pv-box img {
        width: 300px;
        height: auto;
      }
      .pv-box .fade-wrap {
        /* 나타나는 효과가 1초동안 발생 */
        transition: 1s;

        /* 투명도 0 (안보임) */
        opacity: 0;

        /* 왼쪽에서 오른쪽으로 나타나게 하기 위함 */
        position: relative;
        left: -50px;

        margin-bottom: 20px;
      }
      .pv-box .fade-wrap.fade-in {
        /* 투명도 0 (보임) */
        opacity: 1;

        /* 왼쪽에서 오른쪽으로 나타나게 하기 위함 */
        left: 0;
      }
    </style>
  </head>
  <body>
    <div class="pv-box">
      <div class="fade-wrap">
        <h2>첫 번째 섹션</h2>
        <img src="https://source.unsplash.com/featured/:1" alt="img" />
        <p>
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Officiis rem
          voluptatem deleniti quae, nisi quas minus sint explicabo? Similique
          quae minus consequuntur sint, commodi placeat hic ullam necessitatibus
          optio alias?
        </p>
      </div>
      <div class="fade-wrap">
        <h2>두 번째 섹션</h2>
        <img src="https://source.unsplash.com/featured/:2" alt="img" />
        <p>
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Facere optio
          iure labore quo cum excepturi fugit, eum ad velit! Placeat velit a
          officiis architecto perspiciatis possimus aspernatur nostrum veritatis
          maiores?
        </p>
      </div>
      <div class="fade-wrap">
        <h2>세 번째 섹션</h2>
        <img src="https://source.unsplash.com/featured/:3" alt="img" />
        <p>
          Lorem ipsum dolor sit, amet consectetur adipisicing elit. Impedit
          porro atque officiis explicabo dolores error ullam. Ea quidem
          voluptate, ullam odit rem error, maxime voluptas hic, voluptatem
          nesciunt eum in!
        </p>
      </div>
      <div class="fade-wrap">
        <h2>네 번째 섹션</h2>
        <img src="https://source.unsplash.com/featured/:4" alt="img" />
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Modi minus
          doloremque, nam deleniti fugit vel totam dolorum placeat architecto
          consectetur quia incidunt. Nam, iusto quisquam in vero cum assumenda
          rerum?
        </p>
      </div>
    </div>
    <script>
      /* javascript */
      // Intersection Observer 생성
      const observer = new IntersectionObserver(
        (entries, observer) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              // 화면에 들어옴
              entry.target.classList.add("fade-in");
            } else {
              // 화면에서 나감
              entry.target.classList.remove("fade-in");
            }
          });
        },
        // 화면에서 해당 요소가 10% 이상 보일 경우 화면에 들어온 것으로 판단함
        { threshold: 0.1 }
      );

      // 관찰 대상 설정
      const targetElements = document.querySelectorAll(".fade-wrap");
      targetElements.forEach((element) => {
        observer.observe(element);
      });
    </script>
  </body>
</html>

4. 유의사항

  • Intersection Observer는 모던 브라우저에서 지원하므로 호환성에 주의해야 합니다.
  • threshold 값은 관찰 대상이 얼마나 보여야 콜백이 실행될지를 결정합니다. 0부터 1까지의 값을 가질 수 있으며, 0.5는 화면의 50%가 보일 때 콜백이 실행됨을 의미합니다.
  • 간혹 코드를 작성하다보면, 관찰 이벤트가 여러번 중첩하여 등록될 수도 있는데, 이런 경우 불필요한 중첩 이벤트로 인해 브라우저 성능이 떨어질 수도 있습니다. 따라서 Intersection Observer는 더 이상 필요하지 않을 때 명시적으로 해제하는 것이 좋습니다. (ex; 컴포넌트 생명주기)</span >

Destroy 예시:

/* JavaScript */
// 관찰 중지
observer.unobserve(targetElement);

// Observer 해제
observer.disconnect();

5. 참고 자료