HTML/JavaScriptでページ最上部からの位置を取得する方法

2019年7月28日 engineering

こんにちは、kz_moritaです。
最近はVue.js / Nuxt.js あたりで Web フロントを書いたりしています。

今回は、ページの最上部からある特定のDOMの位置座標を取得するのにちょっとつまづいたため、そのことについてまとめておきます。

試した方法

以下の二種類の方法を試しました。

  • HTMLElement.offsetTop
  • Element.getBoundingClientRect().top + window.pageYOffset

結論から言うと、ページの最上部からの位置を取得する仕様は2つ目の方法で実現することができました。

HTMLElement.offetTop

HTMLElement.offsetTopの仕様は以下のサイトに詳しく書いています。

https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetTop

それでは、offsetTopを使ってページ上部からの位置座標を取得してみます。

以下のコードは各DOMの位置を offsetTop から取得して、各DOMの innerText として表示している例です。

  • dom1が一番上に配置されているので0
  • dom2-1は dom1の高さ + dom1,dom2間のmargin + dom2のpadding = 120 + 10 + 10 = 140

となっており、期待通りに正しく動いているように見えます。

offsetTopの問題点

offetTopを取得したい要素の親要素に、 position: relative が指定されていると画面上部からのOffsetを取ることができません。

以下は、 #dom2 { position: relative; } を指定した場合のソースコードです。

dom2-1, dom2-2, dom2-3offsetTop が親要素である dom2 からの位置座標になっていることが分かります。

これはdom2に position: relative を指定することで、dom2-1, dom2-2, dom2-3 の offsetParentがdom2になるためです。

https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetTop

上記サイトに記載されている通り、HTMLElement.offsetTop は offsetParent からの相対距離を取得するプロパティとなります。

positionを指定しないときは、ofsetParentが body になるため、ページ上部からの座標をとることができていたというわけです。

position: relative が指定され血ても当初に仕様を満たすためには、次に説明する方法を使用します。

Element.getBoundingClientRect().top + window.pageYOffset

上記は、

  • Element.getBoundingClientRect() = window.pageYOffset

から成り立っているためそれぞれ別々に説明します。

Element.getBoundingClientRect()

Element.getBoundingClientRectの仕様はいかに記載されています。

https://developer.mozilla.org/ja/docs/Web/API/Element/getBoundingClientRect

getBoundingClientRectでは画面の左上から、描画しているDOMの矩形の情報を取得することができます。 そのため、 getBoundingClientRect().top とすることにより座標を取得することができます。

しかし、この getBoundingClientRect() はHTML文書の左上でなく、 画面の左上 からの位置情報になります。つまり、画面をスクロールすると値が変わってしまいます。

スクロールして上の方に来れば、 getBoundingClientRect().top の値は小さくなっていきます。

そのため、スクロール量を考慮しなければいけません。

window.pageYOffset

仕様はいかに記載されています。

https://developer.mozilla.org/ja/docs/Web/API/Window/pageYOffset

window.pageYOffsetを使用することによって、現在のスクロール量を取得することができます。

ちなみに、 widnow.pageYOffsetwindow.scrollY のエイリアスのためどちらを使っても良いらしいです。 (参考: https://developer.mozilla.org/ja/docs/Web/API/Window/scrollY#Notes)


前述の getBoundingClientRect().top と組み合わせて、 getBoundingClientRect().top + window.pageYOffset とすることで、HTML文書の左上からの座標を取得することが可能になります。

以下ソースコードです。

まとめ

ページ上部からの位置座標を取得したい時には、 dom.getBoundingClientRect().top + window.pageYOffset を使用すれば良いことをまとめました。

これを利用すれば、ユーザーのスクロール量などと比較して色々な演出ができるかと思います。
HTMLは意外と奥が深くてまだまだ知らないことが多そうなので、都度まとめていこうと思います。