티스토리 뷰

Intersection Observer API는 타깃 요소와 상위 요소 또는 최상위 document 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법이다.

Intersection Observer API 필요성

  • 페이지가 스크롤되는 도중에 발생하는 이미지나 다른 콘텐츠의 지연 로딩.
  • 무한 스크롤(infinite-scroll) 구현
  • 광고 수익을 계산하기 위한 용도로 광고의 가시성 보고
  • 사용자에게 결과가 표시되는 여부에 따라 작업이나 애니메이션 수행 여부

Intersection Observer API는 감시하고자 하는 요소가 다른 요소(viewport)에 들어가거나 나갈 때 또는 요청한 부분만큼 요소의 교차 부분이 변경될 때마다 실행될 콜백 함수를 등록할 수 있게 한다.

Intersection Observer API 사용하기

Intersection observer 생성

Intersection observer를 생성하기 위해서는 생성자 호출 시 콜백 함수를 제공해야 한다. 이 콜백은 함수 threshold가 한 반향 혹은 다른 방향으로 교차할 때 실행된다.

let options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

Intersection observer 설정

  • root : 대상 객체의 가시성을 확인할 때 사용되는 뷰포트 요소이며 root는 대상 객체의 조상 요소여야 한다. default는 브라우저의 viewport이다.
  • rootMargin : root가 가진 여백으로 이 속성의 값은 css의 margin 속성과 비슷하며 rootMargin은 root 요소의 각 측면의 bounding box를 수축시키거나 증가시키며, 교차성을 계산하기 전에 적용된다. default는 0이다.
  • threshold : observer의 콜백이 실행될 대상 요소의 가시성 퍼센티지를 나타내는 단일 숫자 혹은 배열이다. 만약 50%만큼 요소가 보였을 때를 탐지하고 싶다면, 값을 0.5로 설정하면 된다. 또는 25% 단위로 요소의 가시성이 변경될 때마다 콜백이 실행되게 하고 싶다면 [0, 0.25, 0.5, 0.75, 1]과 같이 배열을 설정하면 된다. default는 0이며 이는 요소가 1px이라도 보이자마자 콜백이 실행됨을 의미한다. 1.0은 요소의 모든 픽셀이 화면에 노출되기 전에 콜백을 실행시키지 않음을 의미한다.

Intersection Observer Callback 형태

let callback = (entries, observer) => {
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

Intersection observer을 통해 타깃으로 하는 요소 관찰하기

let target = document.querySelector('#listItem');

observer.observe(target);

 

 

Intersection observer 활용

각종 홈페이지와 랜딩페이지의 화면이 전체 렌더링 되지 않고, 스크롤하면 해당 영역이 서서히 화면에 나오는 것을 볼 수 있다. Intersection Observer를 사용해서 아래와 같은 간단한 예제를 만들어 보자.

 

 

IntersectionObserver 생성자를 사용해서 IntersectionObserver 객체를 생성하고, 콜백 함수로 타깃 요소의 isIntersecting 값에 따라 해당 타겟 요소의 class name에 active를 적용한다. isIntersecting 이 true 이면 타겟 요소가 조금이라도 노출된다는 의미이며, false면 더 이상 노출이 되지 않는다는 것을 의미한다. 

// IntersectionObserver 등록
const io = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    console.log(entry)

    if(entry.isIntersecting){
      entry.target.classList.add('active')
    }else{
      entry.target.classList.remove('active')
    }
  })
})

 

관찰하고자 하는 요소들을 생성한 intersectionObserver 객체에 관찰시킨다.

const contentElems = document.querySelectorAll('.content');

// 관찰할 대상을 선언하고, 해당 속성을 관찰시킴
contentElems.forEach((el) => {
	io.observe(el);
})

 

[전체 코드]

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <style>
          body { margin: 0; padding: 0;}
          .section {width: 100%; height: 100vh; display: flex;justify-content: center; align-items: center;}
          .content {position: absolute; padding: 10rem;}
          .title {font-size: 3rem; font-weight: bold; margin-bottom: 2rem; white-space: nowrap; opacity: 0;  transform: translateY(50px);transition: 0.1s 0.1s;}
          .desc {font-size: 1.5rem; line-height: 1.3;  opacity: 0;  transform: translateY(50px);transition: 0.1s 0.1s;}
          .content.active .title {opacity: 1; transform: translateY(0); transition:all 0.5s 0.5s;}
          .content.active .desc {opacity: 1; transform: translateY(0); transition:all 0.5s 0.8s;}
      </style>
      <title>Intersection Observer</title>
  </head>
  <body>
      <section class="section">
          <div class="content">
              <div class="title">Lorem Ipsum is simply dummy text</div>
              <div class="desc">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</div>
          </div>
      </section>
      <section class="section">
          <div class="content">
              <div class="title">Lorem Ipsum is simply dummy text</div>
              <div class="desc">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</div>
          </div>
      </section>
      <section class="section">
          <div class="content">
              <div class="title">Lorem Ipsum is simply dummy text</div>
              <div class="desc">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</div>
          </div>
      </section>
      <script>
          const bgColors = ['#FFAEBC', '#A0E7E5', '#B4F8C8']
          const sectionElems = document.querySelectorAll('section')
          const contentElems = document.querySelectorAll('.content');

          const setColorOfSection = () => {
              sectionElems.forEach((sectionElem, idx) => {
                  sectionElem.style.backgroundColor = bgColors[idx]
              })
          }

          // IntersectionObserver 등록
          const io = new IntersectionObserver(entries => {
              entries.forEach(entry => {
                  console.log(entry)

                  if(entry.isIntersecting){
                      entry.target.classList.add('active')
                  }else{
                      entry.target.classList.remove('active')
                  }
              })
          })

          // 관찰할 대상을 선언하고, 해당 속성을 관찰시킴
          contentElems.forEach((el) => {
              io.observe(el);
          })

          setColorOfSection()
      </script>
  </body>
</html>

 

[참고 자료]

 

Intersection Observer API - Web API | MDN

Intersection Observer API는 타겟 요소와 상위 요소 또는 최상위 document 의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법입니다.Intersection Observer API는 타겟 요소와 상위 요소 또는

developer.mozilla.org

 

Intersection Observer API의 사용법과 활용방법 · Yoon's devlog

Intersection Observer API의 사용법과 활용방법 Web API 중 하나인 Intersection Observer API를 알아보고 어떻게 활용할 수 있는지에 대해 정리한 글입니다. Intersection Observer API(교차 관찰자 API)를 들어본 적이

blog.hyeyoonjung.com

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함