前提として、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
を使えばなんとかできる?