JavaScript | Web API:DOM 拡張 API - ResizeObserver

JavaScript JavaScript
スポンサーリンク

ResizeObserver は「要素の大きさが変わった瞬間を教えてくれるセンサー」

ResizeObserver は、
「特定の要素の幅や高さが変わったときに、それを教えてくれる仕組み」 です。

ウィンドウ全体のサイズ変化なら resize イベントで分かりますが、
「このカードだけ大きさが変わった」「このコンテナだけ高さが変わった」
といった “個々の要素のサイズ変化” を知りたいときに使います。

レイアウトが柔軟な UI
中身のテキスト量によって高さが変わるカード
サイドバーの幅に応じてグラフのサイズを変えたいとき

こういう場面で、ResizeObserver はとても頼りになります。


基本形:「この要素のサイズが変わったら教えて」と頼む

一番シンプルな構造

ResizeObserver の基本構造はこうです。

const observer = new ResizeObserver((entries, observer) => {
  entries.forEach((entry) => {
    console.log(entry);
  });
});

observer.observe(targetElement);
JavaScript

流れを言葉で整理すると、

  1. new ResizeObserver(callback) で「サイズ監視役」を作る
  2. observer.observe(要素) で「この要素を見張って」と依頼する
  3. 要素のサイズが変わるたびに callback が呼ばれる
  4. entries の中に「どの要素がどう変わったか」の情報が入っている

という感じです。

まずは「監視役を作って、要素を observe する」というパターンを覚えてください。

どのサイズが取れるのか(contentRect)

コールバックの中でよく使うのは entry.contentRect です。

const observer = new ResizeObserver((entries) => {
  entries.forEach((entry) => {
    const rect = entry.contentRect;
    console.log("幅:", rect.width, "高さ:", rect.height);
  });
});
JavaScript

contentRect は、
「パディング内側のコンテンツ領域のサイズ」 を表します。

rect.widthrect.height を見れば、
「今この要素は何ピクセルの幅・高さなのか」が分かります。


実例①:要素のサイズを画面に表示してみる

HTML

<div id="box" style="resize: both; overflow: auto; border: 1px solid #333; padding: 16px;">
  右下の角をドラッグしてサイズを変えてみてください。
</div>
<p id="info"></p>

ブラウザによっては、resize: both で要素自体をドラッグしてリサイズできます。

JavaScript

const box = document.querySelector("#box");
const info = document.querySelector("#info");

const observer = new ResizeObserver((entries) => {
  entries.forEach((entry) => {
    const rect = entry.contentRect;
    info.textContent = `幅: ${rect.width.toFixed(0)}px, 高さ: ${rect.height.toFixed(0)}px`;
  });
});

observer.observe(box);
JavaScript

これで、

要素 #box のサイズが変わるたびに
ResizeObserver のコールバックが呼ばれ
contentRect.width / height を画面に表示

という動きになります。

実際にドラッグしてサイズを変えると、
数値がリアルタイムに変わるのが分かるはずです。

ここで掴んでほしいのは、

「ウィンドウ全体のサイズではなく、“特定の要素”のサイズ変化を直接監視できる」

という感覚です。


重要ポイント①:なぜ window.resize ではダメなのか

window.resize は「画面全体」の変化しか分からない

window.addEventListener("resize", ...) は、
ブラウザのウィンドウサイズが変わったときに呼ばれます。

でも、次のようなケースでは不十分です。

フレックスレイアウトやグリッドレイアウトで、
隣の要素のサイズが変わった結果、
この要素の幅が変わる

JavaScript で中身のテキストを増やした結果、
高さだけが変わる

こういう 「ウィンドウサイズとは関係ない要素のサイズ変化」 は、
window.resize では検知できません。

ResizeObserver は、
「その要素自身のサイズが変わったかどうか」を直接見てくれるので、
レイアウトが複雑な UI でも正確に追いかけられます。

レスポンシブなコンポーネントと相性が良い

例えば、

「このカードの幅に応じて、フォントサイズやレイアウトを変えたい」
「このコンテナの幅に合わせて、キャンバスやグラフのサイズを変えたい」

といった「コンポーネント単位のレスポンシブ対応」は、
ResizeObserver があると一気に書きやすくなります。

ウィンドウ全体ではなく、
「コンポーネント自身のサイズ」を基準に振る舞いを変える
という発想が持てるようになると、UI 設計のレベルが一段上がります。


実例②:コンテナの幅に合わせて文字サイズを変える

HTML

<div id="card" style="border: 1px solid #333; padding: 16px;">
  <p id="text">このテキストはカードの幅に応じてサイズが変わります。</p>
</div>

カードの幅を CSS で変えたり、
レスポンシブで変わるようにしておくと効果が分かりやすいです。

JavaScript

const card = document.querySelector("#card");
const text = document.querySelector("#text");

const observer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const width = entry.contentRect.width;

    let fontSize;
    if (width < 300) {
      fontSize = 12;
    } else if (width < 500) {
      fontSize = 16;
    } else {
      fontSize = 20;
    }

    text.style.fontSize = fontSize + "px";
  }
});

observer.observe(card);
JavaScript

ここでやっていることは、

card の幅を ResizeObserver で監視
幅に応じて font-size を切り替える

というシンプルなロジックです。

ウィンドウをリサイズしたり、
CSS でカードの幅を変えたりすると、
テキストサイズが自動で変わるのが分かります。

「コンポーネントの幅に応じて振る舞いを変える」
という典型的な使い方の一つです。


重要ポイント②:entries と entry の中身をもう少しだけ深掘り

entry.target で「どの要素か」が分かる

ResizeObserver は、複数の要素を同時に監視できます。

const observer = new ResizeObserver((entries) => {
  entries.forEach((entry) => {
    console.log("変わった要素:", entry.target);
  });
});

observer.observe(elem1);
observer.observe(elem2);
JavaScript

このとき、
entry.target に「どの要素が変わったか」が入っています。

複数の要素を監視するときは、

entry.target がどの要素かを見て分岐する
あるいは Map などで要素ごとの設定を持っておく

といったパターンになります。

contentRect 以外の情報(borderBoxSize / contentBoxSize)

ブラウザによっては、
entry.borderBoxSizeentry.contentBoxSize など、
より細かいサイズ情報も取れます。

初心者のうちは、
まずは entry.contentRect.width / height だけで十分です。

「パディングやボーダーを含めたサイズ」などが必要になったら、
そのときにドキュメントを見て広げていけばOKです。


重要ポイント③:パフォーマンスと「やりすぎない」感覚

サイズが変わるたびにコールバックが呼ばれる

ResizeObserver は、
サイズが変わるたびにコールバックを呼びます。

つまり、

ウィンドウをリサイズしている間
CSS アニメーションでサイズが変わり続けている間

などは、
かなりの頻度でコールバックが呼ばれることがあります。

その中で重い処理(DOM を大量に組み替える、複雑な計算をするなど)をすると、
パフォーマンスに影響が出る可能性があります。

必要なら「間引き」や「軽い処理」を意識する

例えば、

「サイズが変わったら、ただクラスを付け替えるだけ」
「スタイルを 1 つ変えるだけ」

といった軽い処理なら問題になりにくいですが、

「サイズが変わるたびにグラフを描き直す」
「サイズが変わるたびにレイアウトを組み直す」

といった重い処理をする場合は、

requestAnimationFrame でまとめる
一定時間ごとにまとめて処理する(簡易デバウンス)

などの工夫を入れることもあります。

初心者の段階では、
「サイズ変化のたびにコールバックが走る」という感覚だけ持っておけば十分です。

使い終わったら unobserve / disconnect

監視が不要になった要素は、
observer.unobserve(element) で監視をやめられます。

observer.unobserve(card);
JavaScript

すべての監視をやめたいときは、observer.disconnect() です。

observer.disconnect();
JavaScript

SPA などでコンポーネントが破棄されるときには、
こうした後片付けをしておくと、
無駄な監視が残らず、メモリリークも防ぎやすくなります。


初心者として ResizeObserver で本当に掴んでほしいこと

ResizeObserver は「特定の要素のサイズ変化」を監視するための API
new ResizeObserver(callback) で監視役を作り、observe(要素) で「この要素を見て」と頼む
コールバックの entry.contentRect.width / height で、今の幅・高さが分かる
window.resize では分からない「要素単位のサイズ変化」に対応できる
レスポンシブなコンポーネントや、グラフ・キャンバスのサイズ調整などと相性が良い

まずは、

「要素のサイズを画面に表示するだけ」の小さな例
「幅に応じて文字サイズを変える」例

を自分の手で書いてみてください。

「ウィンドウ全体」ではなく、
「要素そのもののサイズ」をトリガーに UI を変えられる 感覚が一度でも掴めると、
ResizeObserver は「難しい API」ではなく、
レイアウトと仲良くするための、とても心強いセンサーに見えてきます。

タイトルとURLをコピーしました