티스토리 뷰

320x100

이 글은 주니어 개발자가 쓴 글로 오류가 있을 수 있습니다.

문제가 있거나 수정이 필요한 부분은 댓글로 알려주시면 감사하겠습니다.

 

Mozilla 기여자가 작성한 MDN에 대해 CC-BY-SA 2.5 라이선스에 따라 사용할 수 있습니다.


ResizeObserver란?

element의 content box, border box, SVGElement의 bounding box의 변화를 관찰합니다. 리사이징을 다룰 때 발생할 수 있는 무한 콜백 루프와 순환 종속성을 방지합니다. [Test]

 

기존의 resize 이벤트로는 window의 크기 변화만 감지할 수 있었으나, ResizeObserver가 추가되면 개별 element의 크기도 관찰할 수 있습니다.

 

참고) Editor's Draft 단계이기 때문에 추후에 기능이나 문법이 바뀔 수 있습니다.

구문

  • var observer = new ResizeObserver(callback)
  • callback: resize가 발생할 때 호출될 함수.
    • entries: observed 요소의 새로운 크기를 갖는 ResizeObserverEntry(하단 참고).
    • observer: Observer 자기 자신. 특정 조건이 되면 관찰을 중단하는 등의 용도로 사용 가능.

메서드

  • ResizeObserver.disconnect(): 해당 observer에 연결된 모든 element target에 대한 관찰을 중단.
  • ResizeObserver.observer(target, options): 특정 element에 대한 관찰을 시작.
    • options 객체
      • box: 관찰할 box model 설정. 'content-box'(the default), 'border-box', 또는 'device-pixel-content-box'로 설정 가능.
  • ResizeObserver.unobserver(target): 특정 element에 대한 관찰을 중단.

ResizeObserverEntry

borderBoxSize

  • borderBox 크기(그림의 노란색과 그 하위 영역).
  • blockSize: 블록 차원에서의 길이. 수평 쓰기 모드일 경우, 높이. 수직 쓰기 모드일 경우, 너비.
  • inlineSize: 인라인 차원에서의 길이. 수평 쓰기 모드일 경우, 너비. 수직 쓰기 모드일 경우, 높이.

contentBoxSize

  • contentBox 크기(그림의 파란색 박스).
  • blockSize, inlineSize 정의는 위와 동일.

contentRect

  • 관찰 대상의 바뀐 크기를 포함하는 DOMRectReadOnly 객체(사각형의 크기와 위치를 설명).
  • width, height: contentBox의 너비, 높이(그림의 파란색 박스)
  • x, y: 사각형의 x, y, 좌표(그림의 빨간 점 기준, 파란색 박스의 좌측 위 x, y 좌표)
  • left, top: 사각형의 왼쪽, 위쪽 좌표. 일반적으로 x, y와 동일(그림의 빨간 점 기준, 파란색 박스의 왼쪽, 위쪽 좌표)
  • right, bottom: 사각형의 오른쪽, 아래쪽 좌표. 일반적으로 x + width, y + height와 동일(그림의 빨간 점 기준, 파란색 박스의 오른쪽, 아래쪽 좌표)
  • 현재는 위 두 속성보다 잘 지원되지만 웹 호환성을 위해 남아있는 이전 버전 API로 추후 버전에서 사용되지 않을 수 있음.

target

  • 관찰 대상

ResizeObserverEntry 예시

예제 코드

예제 코드는 MDN의 예제 코드에 entries(ResizeObserverEntry) 변화를 보기 위해 1초마다 entries 값을 log로 찍는 throttle만 추가했습니다.

더보기
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ResizeObserver Example</title>
    <style>
      html {
        height: 100%;
        font-family: "helvetica neue", arial, sans-serif;
      }

      body {
        height: inherit;
        margin: 0;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      body > div {
        background-color: #eee;
        border: 1px solid #ccc;
        padding: 20px;
        width: 50%;
        min-width: 320px;
      }

      h1 {
        margin: 0;
      }

      p {
        line-height: 1.5;
      }

      form {
        width: 100%;
      }

      form > div {
        display: flex;
      }

      form label {
        flex: 2;
      }

      form input {
        flex: 3;
      }

      input[type="checkbox"] {
        height: 2rem;
      }
    </style>
  </head>
  <body>
    <div>
      <h1>So what happened?</h1>
      <p>
        And remember, don't do anything that affects anything, unless it turns
        out you were supposed to, in which case, for the love of God, don't not
        do it! Ow, my spirit! I don't want to be rescued. You guys aren't Santa!
        You're not even robots. I've got to find a way to escape the horrible
        ravages of youth. Suddenly, I'm going to the bathroom like clockwork,
        every three hours. And those jerks at Social Security stopped sending me
        checks. Now 'I' have to pay 'them'!
      </p>
      <form>
        <div>
          <label>Observer enabled:</label><input type="checkbox" checked />
        </div>
        <div>
          <label>Adjust width:</label
          ><input type="range" value="600" min="300" max="1300" />
        </div>
      </form>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
    <script src="index.js"></script>
  </body>
</html>
if (window.ResizeObserver) {
  const h1Elem = document.querySelector("h1");
  const pElem = document.querySelector("p");
  const divElem = document.querySelector("body > div");
  const slider = document.querySelector('input[type="range"]');
  const checkbox = document.querySelector('input[type="checkbox"]');

  divElem.style.width = "600px";

  slider.addEventListener("input", () => {
    divElem.style.width = slider.value + "px";
  });

  /* size가 변경될 때, 1초마다 entries 값을 log로 찍음 */
  let logEntries;
  const throttle = _.throttle(function () {
    console.log("entries", logEntries);
  }, 1000);

  const resizeObserver = new ResizeObserver((entries) => {
    for (let entry of entries) {
      if (entry.contentBoxSize) {
        // Checking for chrome as using a non-standard array
        if (entry.contentBoxSize[0]) {
          h1Elem.style.fontSize =
            Math.max(1.5, entry.contentBoxSize[0].inlineSize / 200) + "rem";
          pElem.style.fontSize =
            Math.max(1, entry.contentBoxSize[0].inlineSize / 600) + "rem";
        } else {
          h1Elem.style.fontSize =
            Math.max(1.5, entry.contentBoxSize.inlineSize / 200) + "rem";
          pElem.style.fontSize =
            Math.max(1, entry.contentBoxSize.inlineSize / 600) + "rem";
        }
      } else {
        h1Elem.style.fontSize =
          Math.max(1.5, entry.contentRect.width / 200) + "rem";
        pElem.style.fontSize =
          Math.max(1, entry.contentRect.width / 600) + "rem";
      }
    }
    console.log("Size changed");

    logEntries = entries;
    throttle();
  });

  resizeObserver.observe(divElem /*, { box: "border-box" } */);

  checkbox.addEventListener("change", () => {
    if (checkbox.checked) {
      resizeObserver.observe(divElem);
    } else {
      resizeObserver.unobserve(divElem);
    }
  });
} else {
  console.log("Resize observer not supported!");
}

참고자료

MDN - ResizeObserver

MDN - ResizeObserverEntry

320x100
댓글