3
1

これは何

offsetTopを使ってコンポーネントの位置を取得して発火するイベントが、Safariでだけ挙動がおかしくなったので、その原因を探った時の記録です。

結論

本来offsetTopは最も近い祖先要素(offsetParent)からの距離を取得します。

The HTMLElement.offsetTop read-only property returns the distance from the outer border of the current element (including its margin) to the top padding edge of the offsetParent, the closest positioned ancestor element.

この時、最も近い祖先要素の選定方法がブラウザによって異なることが原因でした。

今回の場合、ChromeやFirefoxでは最も近い祖先要素がsection要素でしたが、Safariでは該当する要素がないためbody要素となっていました。

解決法

ひとまずの解決策として、ChromeやFirefoxで祖先要素になっているsectionposition: relativeを指定しました。

これにより、Safariでも同じsectionが祖先要素となり、計算結果が一致するようになりました。

ただ、そもそもoffsetTopは以下の記事でも紹介されているように挙動が複雑なので、使用しないようにするのが良いと思います。

具体的に起こったこと

ページ内のコンポーネントの位置をoffsetTopを利用して取得し、コンポーネントの位置までスクロールしたらイベントを発火させる処理を作成していました。

const componentPosition =
  componentWrapperRef.current?.offsetTop +
  componentRef.current?.offsetTop

if (scrollY > componentPosition) {
  hogehoge();
}
        
<main>
  <section ref={componentWrapperRef}>
    <div ref={componentRef}>
      {コンポーネントの中身}
    </div>
  </section>
</main>

このとき、ChromeやFirefoxではcomponentRef.current?.offsetTopdivからsectionまでの距離を返しますが、Safariではdivからmainまでの距離を返してしまいました。

結果として、Safariだけイベントが発火する位置がずれてしまっていました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1