要素を移動させるには、座標についてよく知っておく必要があります。
ほとんどの JavaScript メソッドは、2 つの座標系のうちの 1 つを扱います。
- ウィンドウに対する相対座標 –
position:fixed
に似ており、ウィンドウの左上端から計算されます。- これらの座標を
clientX/clientY
と表記します。このような名前の理由は、後でイベントプロパティを学ぶ際に明らかになります。
- これらの座標を
- ドキュメントに対する相対座標 – ドキュメントルートの
position:absolute
に似ており、ドキュメントの左上端から計算されます。- これらを
pageX/pageY
と表記します。
- これらを
ページが先頭までスクロールされ、ウィンドウの左上隅がドキュメントの左上隅と正確に一致している場合、これらの座標は互いに等しくなります。しかし、ドキュメントが移動すると、要素がウィンドウを横切って移動するため、要素のウィンドウに対する相対座標は変化しますが、ドキュメントに対する相対座標は変わりません。
この図では、ドキュメント内の点をとり、スクロール前 (左) とスクロール後 (右) の座標を示します。
ドキュメントがスクロールされた場合
pageY
– ドキュメントに対する相対座標は変わりません。ドキュメントの先頭(スクロールアウト)から数えられます。clientY
– ウィンドウに対する相対座標は変わります(矢印が短くなります)。同じ点がウィンドウの上部に近くなるためです。
要素の座標: getBoundingClientRect
メソッド elem.getBoundingClientRect()
は、組み込みの DOMRect クラスのオブジェクトとして elem
を囲む最小の長方形のウィンドウ座標を返します。
主な DOMRect
プロパティ
x/y
– ウィンドウに対する長方形の原点の X/Y 座標、width/height
– 長方形の幅/高さ (負の値になる可能性があります)。
さらに、派生プロパティがあります。
top/bottom
– 長方形の上/下端の Y 座標、left/right
– 長方形の左/右端の X 座標。
例えば、このボタンをクリックしてウィンドウ座標を確認してください。
ページをスクロールして繰り返すと、ウィンドウに対するボタンの位置が変わるにつれて、ウィンドウ座標(垂直にスクロールする場合は y/top/bottom
)も変化することに気づくでしょう。
これが elem.getBoundingClientRect()
の出力図です。
ご覧のように、x/y
と width/height
は長方形を完全に記述します。派生プロパティは、それらから簡単に計算できます。
left = x
top = y
right = x + width
bottom = y + height
注意してください
- 座標は、
10.5
のような小数点以下の数値になる場合があります。これは正常で、内部的にブラウザは計算に小数を使用します。style.left/top
を設定するときに丸める必要はありません。 - 座標は負の値になる場合があります。例えば、ページがスクロールされて
elem
がウィンドウの上になった場合、elem.getBoundingClientRect().top
は負になります。
x/y
があるのに、なぜ top/left
が存在するのでしょうか。数学的には、長方形はその開始点 (x,y)
と方向ベクトル (width,height)
によって一意に定義されます。したがって、追加の派生プロパティは便宜のためのものです。
技術的には、width/height
が負の値になる可能性があり、これにより、例えばマウス選択を開始点と終了点を適切にマークして表現できる、"方向付けられた" 長方形を作成できます。
width/height
が負の値の場合、長方形は右下隅から始まり、左上に向かって "成長" します。
これが、負の width
と height
を持つ長方形です (例えば、width=-200
、height=-100
)
ご覧のように、この場合、left/top
は x/y
と等しくなりません。
ただし、実際には elem.getBoundingClientRect()
は常に正の幅/高さを返します。ここで負の width/height
について言及するのは、これらの見かけ上重複しているプロパティが実際には重複していない理由を理解していただくためです。
x/y
をサポートしていません。Internet Explorer は、歴史的な理由から x/y
プロパティをサポートしていません。
そのため、ポリフィル(DomRect.prototype
にゲッターを追加)を作成するか、または top/left
を使用することができます。これらは、特に elem.getBoundingClientRect()
の結果で、正の width/height
の場合は常に x/y
と同じです。
ウィンドウに対する相対座標と CSS の position:fixed
の間には、明らかな類似性があります。
しかし、CSS の位置指定では、right
プロパティは右端からの距離を意味し、bottom
プロパティは下端からの距離を意味します。
上記の図を見ると、JavaScript ではそうではないことがわかります。これらの座標を含め、すべてのウィンドウ座標は左上隅から数えられます。
elementFromPoint(x, y)
document.elementFromPoint(x, y)
の呼び出しは、ウィンドウ座標 (x, y)
で最も入れ子になっている要素を返します。
構文は次のとおりです
let elem = document.elementFromPoint(x, y);
例えば、以下のコードは、ウィンドウの中央にある要素のタグをハイライトして出力します。
let centerX = document.documentElement.clientWidth / 2;
let centerY = document.documentElement.clientHeight / 2;
let elem = document.elementFromPoint(centerX, centerY);
elem.style.background = "red";
alert(elem.tagName);
ウィンドウ座標を使用するため、要素は現在のスクロール位置によって異なる場合があります。
elementFromPoint
は null
を返します。document.elementFromPoint(x,y)
メソッドは、(x,y)
が表示領域内にある場合にのみ機能します。
いずれかの座標が負であるか、ウィンドウの幅/高さを超える場合、null
を返します。
以下は、それの確認を怠ると発生する可能性のある一般的なエラーです。
let elem = document.elementFromPoint(x, y);
// if the coordinates happen to be out of the window, then elem = null
elem.style.background = ''; // Error!
「fixed」ポジショニングでの使用
ほとんどの場合、何かを配置するために座標が必要になります。
要素の近くに何かを表示するには、getBoundingClientRect
を使用して座標を取得し、次に CSS の position
を left/top
(または right/bottom
) と共に使用できます。
例えば、以下の関数 createMessageUnder(elem, html)
は、elem
の下にメッセージを表示します。
let elem = document.getElementById("coords-show-mark");
function createMessageUnder(elem, html) {
// create message element
let message = document.createElement('div');
// better to use a css class for the style here
message.style.cssText = "position:fixed; color: red";
// assign coordinates, don't forget "px"!
let coords = elem.getBoundingClientRect();
message.style.left = coords.left + "px";
message.style.top = coords.bottom + "px";
message.innerHTML = html;
return message;
}
// Usage:
// add it for 5 seconds in the document
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);
ボタンをクリックして実行してください。
このコードは、メッセージを左、右、下、に表示するように変更したり、CSS アニメーションを適用して「フェードイン」させたりすることができます。要素のすべての座標とサイズがあるので、それは簡単です。
ただし、重要な点に注意してください。ページがスクロールされると、メッセージはボタンから離れていきます。
その理由は明らかです。メッセージ要素は position:fixed
に依存しているため、ページがスクロールしてもウィンドウの同じ場所に残ります。
これを変更するには、ドキュメントベースの座標と position:absolute
を使用する必要があります。
ドキュメント座標
ドキュメントに対する相対座標は、ウィンドウではなくドキュメントの左上隅から始まります。
CSS では、ウィンドウ座標は position:fixed
に対応し、ドキュメント座標は最上位の position:absolute
に似ています。
position:absolute
と top/left
を使用して、ドキュメントの特定の場所に何かを配置し、ページスクロール中にそこに残るようにすることができます。しかし、最初に正しい座標が必要です。
要素のドキュメント座標を取得するための標準的なメソッドはありません。しかし、記述するのは簡単です。
2 つの座標系は、次の式で接続されています。
pageY
=clientY
+ スクロールアウトしたドキュメントの垂直部分の高さ。pageX
=clientX
+ スクロールアウトしたドキュメントの水平部分の幅。
関数 getCoords(elem)
は、elem.getBoundingClientRect()
からウィンドウ座標を取得し、現在のスクロールを追加します。
// get document coordinates of the element
function getCoords(elem) {
let box = elem.getBoundingClientRect();
return {
top: box.top + window.pageYOffset,
right: box.right + window.pageXOffset,
bottom: box.bottom + window.pageYOffset,
left: box.left + window.pageXOffset
};
}
上記の例で position:absolute
で使用した場合、メッセージはスクロール時に要素の近くに留まります。
変更された createMessageUnder
関数
function createMessageUnder(elem, html) {
let message = document.createElement('div');
message.style.cssText = "position:absolute; color: red";
let coords = getCoords(elem);
message.style.left = coords.left + "px";
message.style.top = coords.bottom + "px";
message.innerHTML = html;
return message;
}
まとめ
ページ上の任意の点には座標があります。
- ウィンドウに対する相対座標 –
elem.getBoundingClientRect()
。 - ドキュメントに対する相対座標 –
elem.getBoundingClientRect()
に現在のページスクロールを加えたもの。
ウィンドウ座標は position:fixed
での使用に最適であり、ドキュメント座標は position:absolute
でうまく機能します。
両方の座標系には長所と短所があります。CSS の position
absolute
と fixed
のように、どちらか一方または両方が必要な場合があります。
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行以上の場合にはサンドボックス(plnkr、jsbin、codepen…)を使用してください。