ある要素とある要素の大きさを連動させたい時、普通はCSSを使います。width: 75%
とかそういうのです。しかしながら独自の定義である要素とある要素の大きさを関連付けたい時があります。そういった時には ResizeObserver を使うことで目的を達成しやすくなります。
ResizeObserver – Web API | MDN
ResizeObsergver とはその名の通り大きさの変化を監視する者です。具体的には次の様に使います。
// 監視用の ResizeObserver インスタンスを用意 // 監視対象要素の大きさが変わるたびにこれに渡したコールバックが走る const textareaObserver = new ResizeObserver(resizeHandler); // ResizeObserver インスタンスに監視対象要素を登録 textareaObserver.observe( document.querySelector('#observe-tgt') ); /** 監視対象要素の大きさが変わるたびに実行される関数 */ function resizeHandler(entries) { for (let entry of entries) { console.log({ entry }) } }
大きさが変わったことを検知したい対象を ResizeObserver インスタンスに渡し、インスタンスを生成する際にあらかじめ大きさが変わった時に行いたい動作を渡しておく感じです。行いたい動作は例によってコールバックで定義します。このコールバックに渡される値は ResizeObserverEntry の配列と決まっており、ResizeObserverEntryは次のリンクが詳しく、
ResizeObserverEntry – Web API | MDN
次の型定義の通りになっています。
type ResizeObserverEntry = { readonly borderBoxSize: ReadonlyArray<{ // テキストの方向で幅と高さが入れ替わります readonly blockSize: number; // 高さ readonly inlineSize: number; // 幅 }>; readonly contentBoxSize: ReadonlyArray<{ readonly blockSize: number; readonly inlineSize: number; }>; readonly contentRect: { readonly bottom: number; readonly height: number; readonly left: number; readonly right: number; readonly top: number; readonly width: number; readonly x: number; readonly y: number; toJSON(): any; }; readonly devicePixelContentBoxSize: ReadonlyArray<{ readonly blockSize: number; readonly inlineSize: number; }>; readonly target: Element; };
読み取りにして様々な視点からの幅、高さを得られます。contentRect や target を使うことで位置も特別新たにクエリを発行することなく得られます。
これを使うことで様々なことができます。例えば、次の様にある要素とある要素をDOM構造やCSSを無視して連動させられます。テキストボックスの右下の斜線をドラッグすると赤い四角の大きさも合わせて変わります。
// 監視用の ResizeObserver インスタンスを用意 // 監視対象要素の大きさが変わるたびにこれに渡したコールバックが走る const textareaObserver = new ResizeObserver(resizeHandler); // ResizeObserver インスタンスに監視対象要素を登録 textareaObserver.observe( document.querySelector('#observe-tgt') ); const changeSizeTgt = document.querySelector('#change-size-tgt'); /** * 監視対象要素の大きさが変わるたびに実行される関数 * @param {ResizeObserverEntry[]} entries */ function resizeHandler(entries) { for (let entry of entries) { // 渡された幅と高さに同期させたい要素の幅と高さを変更する changeSizeTgt.style.height = entry.contentBoxSize[0].blockSize + 'px'; changeSizeTgt.style.width = entry.contentBoxSize[0].inlineSize + 'px'; } }