junyeokk
Blog
JavaScript·2025. 09. 22·3

ResizeObserver

특정 요소의 크기가 바뀔 때 이를 감지해야 하는 상황이 있다. 가장 먼저 떠오르는 방법은 window.resize 이벤트다.

javascript
window.addEventListener("resize", () => {
  // 브라우저 창 크기가 바뀔 때만 호출됨
});

그런데 이 방식은 브라우저 창 크기가 바뀔 때만 동작한다. 사이드바를 여닫거나, 다른 요소가 확장/축소되면서 특정 컨테이너의 크기가 바뀌는 경우에는 resize 이벤트가 발생하지 않는다. 브라우저 창 자체의 크기는 그대로이기 때문이다.

ResizeObserver는 이 문제를 해결한다. 특정 DOM 요소의 크기 변화를 직접 관찰하기 때문에, 원인에 관계없이 해당 요소의 크기가 바뀌면 콜백이 실행된다.


기본 사용법

ResizeObserver는 생성, 관찰 등록, 관찰 중지 세 단계로 사용한다.

javascript
// 1. Observer 생성
const observer = new ResizeObserver(callback);

// 2. 관찰할 요소 등록
observer.observe(targetElement);

// 3. 관찰 중지
observer.unobserve(targetElement);
observer.disconnect(); // 모든 요소 관찰 중지

IntersectionObserver와 사용 패턴이 동일하다. observe()로 여러 요소를 등록할 수 있고, unobserve()로 특정 요소만, disconnect()로 모든 요소의 관찰을 중지한다.


콜백 함수

관찰 중인 요소의 크기가 변하면 콜백이 실행된다. 콜백은 entries 배열을 인자로 받는데, 각 entry에서 해당 요소의 크기 정보를 확인할 수 있다.

javascript
const callback = (entries) => {
  entries.forEach((entry) => {
    const { width, height } = entry.contentRect;
    console.log(`크기 변경: ${width} x ${height}`);
  });
};

contentRect는 padding을 제외한 콘텐츠 영역의 크기를 반환한다. 더 정밀한 크기가 필요하면 borderBoxSizecontentBoxSize를 사용할 수 있다.

속성설명
contentRect콘텐츠 영역의 위치/크기 (DOMRectReadOnly)
contentBoxSize콘텐츠 박스 크기 (padding 제외)
borderBoxSize보더 박스 크기 (border, padding 포함)
devicePixelContentBoxSize디바이스 픽셀 단위의 콘텐츠 박스 크기
target관찰 중인 DOM 요소

window.resize와의 차이

window.resizeResizeObserver
감지 대상브라우저 창 전체지정한 개별 요소
사이드바 여닫기감지 못함감지
CSS 레이아웃 변화감지 못함감지
다른 요소의 확장/축소감지 못함감지
브라우저 창 리사이즈감지감지 (요소 크기가 바뀌는 경우)

크기가 변하는 상황들

ResizeObserver가 감지하는 "크기 변화"는 다양한 원인에서 발생한다.

  • 브라우저 창 크기 변경 (이 경우 window.resize도 동작)
  • CSS 미디어 쿼리에 의한 레이아웃 변경
  • 사이드바, 패널 등의 여닫기
  • JavaScript로 요소의 스타일을 직접 변경
  • 텍스트 콘텐츠가 추가/제거되면서 높이가 바뀌는 경우
  • CSS flex, grid 레이아웃에서 다른 자식 요소의 크기 변화로 인한 연쇄 변경

활용 예시

컨테이너 크기에 맞춰 캔버스 리사이징

컨테이너 크기가 바뀔 때 캔버스도 따라서 크기를 조정해야 하는 경우에 유용하다.

javascript
const observer = new ResizeObserver((entries) => {
  const { width, height } = entries[0].contentRect;
  canvas.width = width;
  canvas.height = height;
  redraw();
});

observer.observe(document.querySelector(".canvas-container"));

반응형 차트

차트 라이브러리를 사용할 때, 컨테이너 크기에 따라 차트를 다시 그려야 하는 경우다.

javascript
const observer = new ResizeObserver((entries) => {
  const { width, height } = entries[0].contentRect;
  chart.resize(width, height);
});

observer.observe(document.querySelector(".chart-container"));

텍스트 오버플로우 감지

요소의 크기가 바뀌면서 텍스트가 넘치는지 확인하고, 넘치면 "더보기" 버튼을 표시하는 패턴이다.

javascript
const observer = new ResizeObserver((entries) => {
  entries.forEach((entry) => {
    const el = entry.target;
    const isOverflowing = el.scrollHeight > el.clientHeight;
    toggleShowMoreButton(el, isOverflowing);
  });
});

observer.observe(document.querySelector(".text-content"));

React에서 사용

React에서는 커스텀 훅으로 만들어 사용하면 편하다.

tsx
function useElementSize(ref: RefObject<HTMLElement | null>) {
  const [size, setSize] = useState<{ width: number; height: number } | null>(null);

  useEffect(() => {
    const element = ref.current;
    if (!element) return;

    const observer = new ResizeObserver(([entry]) => {
      const { width, height } = entry.contentRect;
      setSize({ width, height });
    });

    observer.observe(element);
    return () => observer.disconnect();
  }, [ref.current]);

  return size;
}

이 훅을 사용하면 요소의 크기가 바뀔 때마다 size 상태가 업데이트된다. cleanup 함수에서 disconnect()를 호출해서 컴포넌트가 언마운트될 때 메모리 누수를 방지한다.

tsx
function MyComponent() {
  const containerRef = useRef<HTMLDivElement>(null);
  const size = useElementSize(containerRef);

  return (
    <div ref={containerRef}>
      {size && <p>현재 크기: {size.width} x {size.height}</p>}
    </div>
  );
}

주의사항

ResizeObserver 콜백 안에서 관찰 중인 요소의 크기를 다시 바꾸면 무한 루프가 발생할 수 있다. 브라우저는 이를 방지하기 위해 한 프레임에 하나의 ResizeObserver 콜백만 처리하고, 무한 루프가 감지되면 ResizeObserver loop completed with undelivered notifications 에러를 콘솔에 출력한다. 이 에러 자체는 치명적이지 않지만, 콜백 안에서 크기를 변경하는 로직은 피하는 게 좋다.


브라우저 지원

모든 최신 브라우저에서 지원한다.

  • Chrome 64+
  • Firefox 69+
  • Safari 13.1+
  • Edge 79+

정리

  • window.resize는 브라우저 창 크기만 감지하지만, ResizeObserver는 개별 DOM 요소의 크기 변화를 감지한다.
  • CSS 레이아웃 변화, 사이드바 여닫기, 다른 요소의 크기 변동 등 원인에 관계없이 크기가 바뀌면 콜백이 실행된다.
  • IntersectionObserver와 사용 패턴이 동일해서(observe/unobserve/disconnect), 하나를 알면 다른 하나도 쉽게 쓸 수 있다.

관련 문서