Post

Intersection Observer API로 화면 요소 감지하기

웹에서는 다양한 화면 크기와 장치에 대응하여 요소들의 가시성을 관리해야 합니다. 특히, Intersection Observer API는 페이지 로딩 시에 모든 이미지나 미디어를 한 번에 로딩하지 않고 화면에 특정 이미지나 미디어가 나타날 때 로딩하는 방식을 채택 하여 성능을 개선하거나 사용자가 특정 광고 영역으로 스크롤할 때 해당 광고의 노출 여부를 감지하고 트래킹할 수 있는 기능, 이 밖에도 무한로딩, 스크롤 기반 애니메이션 등 다양한 상황에서 쓰일 수 있습니다.

따라서 프론트엔드 개발자라면 Intersection Observer API에 대한 기본적인 사용법을 익혀두고 나중에 실무나 사이드 프로젝트에 응용해서 쓸 수 있어야 한다고 생각 합니다.

또한 이 글에서는 Intersection Observer API가 탄생하게된 배경 또는 정의를 쓰는 글이라기보다 작은문제가 주어졌을 때 제가 API를 어떻게 활용해아할 지를 고민한 글 입니다.

이 글은 2024-01-02 에 업데이트 되었습니다.

이 글은 HTML, CSS , JavaScript에 대한 기본적인 지식을 알고 있어야 합니다.

프로젝트 요구 사항 정의

Alt text

저는 api나 다른 새로운 기술을 익힐 때 간단하게라도 프로젝트를 생각해서 만들어보고 적용해 보는 것을 선호합니다. 따라서 이 글에서도 아주아주 간단하게 위와 같은 Intersection Observer API로 요소를 감지하면 pink였던 배경색이 아름다운 skyblue 색이 되는 프로젝트를 만들어 보겠습니다.

결과 확인의 CodePen에서 모든 코드와 실행화면을 확인하실 수 있습니다!

기본적인 사용법

간단한 프로젝트에 Intersection Observer API를 사용하기 이전에 저는 아래와 같은 3단계를 지정하여 사용법을 이해했습니다.

1.콜백함수와 옵션 작성하기

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
let options = {
  // 대상 객체의 가시성을 확인할 때 사용되는 뷰포트 요소입니다. 조상 요소여야함
  // 등록하지 않으면 자동으로 뷰포트 기준으로 됩니다.
  root: document.querySelector("조상요소"),
  // root 가 가진 여백을 지정할 수 있습니다. CSS의 margin 속성과 유사하게
  // 상,우 하,좌 로 설정이 가능합니다.
  rootMargin: "0px",

  // observer의 콜백이 실행될 대상 요소의 가시성 퍼센티지를 나타내는 단일 숫자 혹은 숫자 배열입니다.
  // 만일 50%만큼 요소가 보여졌을 때를 탐지하고 싶다면, 값을 0.5로 설정하면 됩니다.
  threshold: 1.0,
};

let callback = (entries, observer) => {
  entries.forEach((entry) => {
    // 각 항목들 중에서 관찰된 하나의 교차 변경을 설명합니다.
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

2. IntersectionObserver를 등록하기 (콜백함수와 옵션이 매개변수로!)

1
const io = new IntersectionObserver(callback, options);

3. 관찰할 대상을 선언하고 관찰시키기

1
2
3
4
const observer = document.querySelectorAll(".box");
divEl.forEach((el) => {
  io.observe(el);
});

전체 코드

전체 코드 다음과 같습니다. callback함수의 entry옵션의 설명이 궁금하시면 여기를 클릭하세요!

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
32
33
34
35
36
// 1. 콜백함수와 옵션 작성하기

let options = {
  // 대상 객체의 가시성을 확인할 때 사용되는 뷰포트 요소입니다. 조상 요소여야함
  // 등록하지 않으면 자동으로 뷰포트 기준으로 됩니다.
  root: document.querySelector("#조상요소"),
  // root 가 가진 여백을 지정할 수 있습니다. CSS의 margin 속성과 유사하게
  // 상,우 하,좌 로 설정이 가능합니다.
  rootMargin: "0px",

  // observer의 콜백이 실행될 대상 요소의 가시성 퍼센티지를 나타내는 단일 숫자 혹은 숫자 배열입니다.
  // 만일 50%만큼 요소가 보여졌을 때를 탐지하고 싶다면, 값을 0.5로 설정하면 됩니다.
  threshold: 1.0,
};

let callback = (entries, observer) => {
  entries.forEach((entry) => {
    // 각 항목들 중에서 관찰된 하나의 교차 변경을 설명합니다.
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

// 2. `IntersectionObserver`를 등록하기
const io = new IntersectionObserver(callback, options);

// 3. 관찰할 대상을 선언하고 관찰시키기
const observer = document.querySelectorAll(".box");
divEl.forEach((el) => {
  io.observe(el);
});

프로젝트에 적용

위에서 사용법을 알았으니 이제 우리 프로젝트에 적용해 봅시다.

우리가 사용할 요소인 box라는 클래스를 가진 div요소를 여러개 생성하고 CSS로 크기와 색을 스타일링 해 줍니다.

1
2
3
4
5
6
7
8
9
10
11
<body>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
.box {
  width: 200px;
  height: 200px;
  background-color: pink;
  margin: 5rem auto;
  border-radius: 10px;
  transition: all 0.5s ease;
}

.active {
  background-color: skyblue;
}

위에 설명한 사용법과 같이 단계 1을 작성했습니다. 단계 1에서 rootrootMargin은 생략해도 되는 값이기에 생략해 주었고 뷰포트에서 보여지는 기준인 threshold0.5로 지정하였습니다.

콜백 함수는 뷰포트의 요소들의 배열인 entries 들을 기준으로 가시비율인 intersectionRatio가 0.5 이상이라면 active 클래스를 아니라면 제거해 주었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. 콜백함수와 옵션 작성하기
let options = {
  threshold: 0.5,
};

let changeColor = (entries, observer) => {
  entries.forEach((entry) => {
    if (entry.intersectionRatio > 0.5) {
      entry.target.classList.add("active");
    } else {
      entry.target.classList.remove("active");
    }
  });
};

이제 단계 2단계 3은 위에서 설명한 것처럼 옵저버를 선언하고 관찰할 대상을 관찰 시키면 됩니다.

1
2
3
4
5
6
7
8
// 2. 옵저버 등록하기
const io = new IntersectionObserver(changeColor, { threshold: 0.5 });

// 3. 관찰할 대상을 선언하고 관찰시키기
const boxEl = document.querySelectorAll(".box");
boxEl.forEach((el) => {
  io.observe(el);
});

결과

스크롤을 천천히 내려보세요!

See the Pen 인터섹션 옵저버 사용하기 by osh6006 (@osh6006) on CodePen.

결론

Intersection Observer API는 DOM조작이나 스크롤 이벤트를 구현할 때 자주 사용되는 방법 중 하나 입니다. 이번 포스트 에서는 javascript에서 사용하는 방법을 알아 봤으니 다음에는 react에서 커스텀 훅을 사용해서 랜더링 최적화 하는 간단한 프로젝트도 추후에 포스팅 해봐야 겠다는 생각이 들었습니다.

참고 사이트

https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry

This post is licensed under CC BY 4.0 by the author.