当然の話でした。皆さんは何が間違っているか、わかりますか?
resize/ResizeObserverはどちらもJavaScriptで、表示要素のサイズが変更されたときにキャッチアップする仕組みです。
どっち使えばいいかわかんないけど、とりあえず新しいResizeObserver使っとけばいいっしょ? と思ったあなた、表題の罠にハマるタイプです。
この二つは明確な違いがあります。それが監視対象です。
| 対象 | 概要 |
|---|---|
| resize | windowを対象にできる |
| ResizeObserver | windowを対象にできず、HTML要素のみ対象にできる |
え〜、でもdocument.bodyを対象にすればResizeObserverでも同じようにできるんじゃね? と思ったあなた、残念できません。正確にいうと、できる場合もあれば、できない場合もあります。
stack-overflowによると、document.bodyを対象としたときheightの変更が監視されていないとか、CSSでheight:100%にすれば監視できると話しています。要点をわかりやすく言いましょう。そもそもCSSではHTML要素のサイズを固定できてしまうので、サイズ変更が起こらなくなります。(!)
リサイズ監視してもリサイズが起きない
index.html
<style>body { width:800px; height:600px; }</style> <script> window.addEventListener('DOMContentLoaded', (event) => { new ResizeObserver(()=>{console.log('ResizeObserver')}).observe(document.body) }); </script>
<style>にあるように、bodyの幅と高さを固定しています。document.bodyの要素リサイズを監視しても、リサイズが起きません。
ためしにブラウザの窓サイズを変えてみましょう。最大化をやめて画面の端をマウスで掴み、ぐにぐにと動かして大きさを変えてみます。しかし一度もログが出ません。bodyサイズはCSSにより固定されているのでサイズ変更が起きず、ResizeObserverでリサイズ監視してもキャッチアップされないのです。
(ログをHTML要素として表示するコード)
<style>body { width:800px; height:600px; }</style> <script> window.addEventListener('DOMContentLoaded', (event) => { window.addEventListener('resize', (event)=>{log()}); function log() { const msg = `${window.innerWidth}x${window.innerHeight}` console.log(msg) document.querySelector('textarea').value += msg + '\n' } }); </script> <textarea></textarea>
当たり前じゃん
はい、そうですね。ごめんなさい。
windowはCSSでサイズ固定できないはずなので、そんな罠はありません。windowをresizeイベントで監視すれば、たとえbodyサイズを固定しようとも、ちゃ〜んとキャッチアップしてくれます。
<style>body { width:800px; height:600px; }</style> <script> window.addEventListener('DOMContentLoaded', (event) => { window.addEventListener('resize', (event)=>{console.log('resize')}); }); </script>
クイズの答えです。「ResizeObserverで窓リサイズをキャッチしようとしてハマった」ということでしたが、これの何が間違っていたでしょうか。その答えは、窓リサイズをキャッチするのはResizeObserverでなくresizeイベントであるべき、でした。
結論
窓リサイズ監視するときはwindowに対してresizeイベントを用いること。
document.bodyをResizeObserverで監視しても、CSSでbody { width:800px; height:600px; }のようにサイズ固定されるなど何らかの条件によってサイズ変更しない場合があり、キャッチアップできないことがある。