【HTML/JavaScript】位置情報扱い方法まとめ【scroll/mouse/element/document/window】


JavaScriptなどで位置に関する処理を行うときに、勘違いや間違い、わかりにくいところが多いので
大分混乱しました。

時間節約のため、覚えているうちに、ポイントをまとめておきたいと思います。
(MDNのFirefoxベース)

うっかりしていた、間違っていた、間違いやすそう、あいまいに理解して問題が起こりそうなところには😰を置きました。

大きく3つの座標系

まず初めに自分が何の値を使っているのか、話しているのかを明確にするために
次の基準点を理解しないといけない。

表す座標系 呼び方
Webページ内での位置
(document文書の左上隅を基準)
ローカル座標⇒ドキュメント座標系とここでは呼ぶことにする。
ブラウザ、タブウインドウ内での位置
(ウインドウ左上を基準)
ビューポート
デスクトップでの位置 グローバル座標
スクリーン座標

覚え方:マウスなどのイベントはよく考えれば、ブラウザ内の位置であることは納得がいくし、エレメントでの位置やスクロール位置はページドキュメント内の位置になる。ビューポートは見た目視点なので、windowだと理解しやすい。ローカルという名称だけはイメージがしにくい。
mousedown - Event reference | MDN

絶対座標? →  ローカル? グローバル?か実はあいまいな表現だとわかる。

位置を覚えるときスコープが広い場合 どの座標系かを変数名の命名規則につけておくべき。

補足

 padding/content edge

座標系を考えるうえで、要素の左上が実際どの点を指すのか正確に知っておく必要がある。考えるポイントとしては、HTMLのレイアウトにおけるボックスの位置関係が大事。

  • padding edge:  border と padding の境目
  • content edge : padding と content の境目  (content は テキストなどが描かれる位置)

その前の、 boarder edge , margin edge も同様に外側との境界
CSS ボックスモデルの紹介 - CSS | MDN

実は左上は contentのところ。予想以上に内側にある。
box-sizingで設定せずに 幅100%指定しているのは実はイメージが間違っている。😰

CSSでいう 100vw はビューポート座標で、100% は content edgeのサイズになる。
bodyが100%であれば、スクロールバーに影響されずに100%の幅でブラウザは表示させるから element.clientWidthが スクロールバーの幅を除いたウインドウ幅になる。

スクロールバー

全てのスクロールバーは クライアント内に存在

border > padding(scrollも) > テキストコンテンツ

にあり、実は、右端のスクロールバーも同じ考えで、ウインドウに付属しているものではなく、各要素の一つであるdocumentのclient内に要素に表示しきれていない範囲があるから、要素内で出現させているという設計思想だった。😰

document.documentElement

HTML文書では htmlです。document.bodyよりも上位ということ。
document.documentElement - Web API インターフェイス | MDN

単位

基本的には Integer で px単位を指定・取得する。もちろん styleなどは "10px"のように指定する。

位置情報関連の取得/設定とオブジェクトの関係

 座標系の取得

デスクトップ基準のスクリーン座標

使用方法 意味
window.screenX ウインドウの位置
window.screenX - Web API インターフェイス | MDN
event.screenX マウスなどイベント時の位置
Event reference | MDN

  ちなみに、

  • window.mozInnerScreenX  は スクリーン座標系で、 window内の左上のピクセル位置。

ウインドウのビューポート座標

使用方法 意味
event.clientX イベントの発生場所
element.getBoundingClientRect()

ビューポート
element.getBoundingClientRect - Web API インターフェイス | MDN

補足:
  window.innerWidthは ビューポート内の幅   100vwに近いが下に記載したように デフォはcontent edgeのサイズ 

ドキュメント内のローカル座標

使用方法 意味
window.scrollX
window.page XOffset
ウインドウのスクロール位置(document左上からwindow左上)
(pageXOffsetは MDNではエイリアス)
window.scroll() ウインドウのスクロール位置を設定

 

オブジェクトごと

オブジェクト プロパティ 座標系
window screenX   スクリーン
scrollX    / scroll() /scrollTo() ローカル/ドキュメント
event clientX       ビューポート
screenX   スクリーン
pageX ローカル/ドキュメント
(正式前)
offsetX 関係なし:event.targetとの相対位置
(正式前)
element getBoundingClientRect () ビューポート
document.elementFromPoint()  ドキュメント
getClientRects() ビューポート
scrollLeft       関係なし  表示位置のずれ
(ある意味要素のビューポートサイズが widthで、
 その中のスクロール位置が scrollLeft、要素の大きさが clientWidth)
clientLeft        関係なし  padding edge から border edgeまでの横幅のずれ😰
(パディングから外側のマージンへの距離であるためボーダー幅)
element.clientLeft - Web API インターフェイス | MDN

要素の幅と高さ

オブジェクト
サイズの取得
取得方法
screen window.screen.width
window.screen.availWidth
Screen - Web API インターフェイス | MDN
window window.outerWidth  (ウインドウ外観)
                          /  設定は reseizeTo()  ポップアップ画面だけ
                                    window.resizeBy()は同様ですが差分を指定します。
window.innerWidth (ウインドウ内)
element element.getBoundingClientRect().width
document document.documentElement.getBoundingClientRect().width

 

座標変換

ローカル/ドキュメント座標とビューポート座標


ウインドウの左上の位置(ローカル座標)が scrollXとなるのでその基準点の相対差分で求める。

スクロール位置と、マウスクリック位置と、要素(element)の位置の相互比較のケース。

window.scrollX + mouseevent.clientX = element.pageX
(座標系から考えると不自然だが)
→要素のウインドウ位置を求めるとき :clientX = pageX - scrollX

  • ドキュメント→ビューポート: scrollX を引く
  • ビューポート→スクリーン:  screenX を足す。

 

よくありそうな使用例

親子要素の位置の関係性

ビューポート座標(ウインドウ内の相対位置)が getBoundingClientRect() で分かるので、
parentNode など使って、取得した値の差異を求めればいい。

スクロール位置 window.scrollXを足せば、ローカル座標(ドキュメント内)に変換できる。

スクロール位置

window.scrollX, scrollYで取得し、 window.scroll()で設定する。


document.body.scrollTop/Leftがほぼ同じ値として使えるが、
本質的には違うものなのでずれるときがある。
例えば width(表示の大きさ) < clientWidth(要素の大きさ) の時は
client描画領域として over-flow 等の処理や大きさの考慮が必要。😰

マウス

event.clientX は ビューポート座標。
event.targetは ElementなのでgetBoundClientRect()を使えば、そのまま比較できる。

ただしイベントによっては、
event.target や event.currentTargetの指すものが nullになったり、別の要素となることもあるので
ちゃんとマニュアルで意味するところを確認して注意する必要がある。
※親要素の場合とか、ドラッグ先とか、イベント生成元とかケースが違う。😰

マウスイベント

clientX/Y を使う。

pageX , offsetX などは 正式ではない。
MouseEvent - Web API インターフェイス | MDN

スクロールバーの幅

求められない。

Element - Web APIs | MDN

一応ほかの情報源もリストアップ。


clientWidthから求めようとしているが、環境によるらしいので
16pxあたりの決め打ちでまずまずいいと思う。

document.body.clientWidth は幅100%表示したときに、内部を最大値まで表示していてくれるので
その前提で innerWidthとの差分がスクロールバーの幅になっているように見えるときがある。😰

要素のscroll と client

client は その Box全体の大きさを表す。つまり100%表示されていれば、見た目のサイズが等しくなる。一部しか表示されていない時に表示外に飛び出すイメージ。 (widthを考えれば意味が分かってくる。)
scrollの位置は0になるが、一番上のスクロール量に似た値が取得できる。

clientWidth(実態)  > width (表示上のサイズ) と scrollY (相対的な表示のずれ位置)の考慮で関係性がわかる。

clientWidthは スクロールバーを除いたサイズではなく、 幅が100%治まっているとき、ウインドウのスクロールバーを除いたサイズに見える。
ウインドウの幅は スクロールバーを除いたサイズではなく、別の基準の値。
body.clientWidthと window.innerWidthは全くの別物

スクロールバーの幅は、指定されていなければ暗に推測するぐらいしかできないっぽい。


大きい要素 TextArea , DIVの中身を詳しく解析したい時

以下の関数でチクチクやっていくしかない。
※ビューポイント座標系 

Element.getClientRects() - Web APIs | MDN

指定した位置で要素を取得

document.elementFromPoint(x,y);

※ドキュメント座標系
document.elementFromPoint - Web API インターフェイス | MDN

Delicious にシェア
Digg にシェア
reddit にシェア
LinkedIn にシェア
LINEで送る
email this
Pocket




コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です