前提として、ResizeObserver は、CSS transformによる要素サイズの変化を検知しない。CSSの transform 属性を動的に書き換えても ResizeObserver は検知してくれない。
Observations will not be triggered by CSS transforms.
Resize Observer
framer-motionというライブラリで transform 属性を書き換えて scale(...) の値を動的に書き換えるようなアニメーションをしつつ、その子要素でreact-use-measureの useMeasure フックを使って子要素のサイズを測定するときにハマった。
useMeasure フックは内部で ResizeObserver を使っているが、これとframer-motionによるアニメーションを組み合わせると、要素の大きさとしてアニメーション途中の値が採用されてしまう。欲しいのはアニメーション完了時 (transform: scale(1) になる) の大きさなので、これではうまくいかない。
困ったのでreact-use-measureの実装を読みにいったら、つい最近react-use-measureの新しいバージョンが出ており、その中でも目を引くcommitがあった。
useMeasure フックの引数に offsetSize というオプションが追加されていた。この値を true にすると、要素の大きさとして常に offsetWidth offsetHeight を採用するようになる。
要素の大きさについてMDNを参照すると、以下のように求めていたものであることが例示付きで書いてあった。
offsetWidthおよびoffsetHeightは要素のレイアウトの幅と高さを返し、getBoundingClientRect()はレンダリングの幅と高さを返します。例として、要素にwidth: 100px;とtransform: scale(0.5);がある場合getBoundingClientRect()は幅として 50 を返し、offsetWidthは 100 を返します。
要素の寸法の決定 - Web API | MDN
ということで、react-use-measureのバージョンを最新版にした上で offsetSize オプションを true に設定することで解決できた。
ところで今回の要件には入らなかったけど、CSS transformを動的に書き換える場合の要素の大きさの変化を検知するいい方法はあるのだろうか。要素の style 属性を書き換えるならMutationObserverを使えばなんとかできる?