😑
JSでの主な基準のサイズ・要素のサイズと座標・ポインターの座標取得まとめメモ
要素のサイズやポインターの座標など色々プロパティがありますが、その時々に調べて使用していました。しかしその作業が非常に煩わしいので、いい加減全体的にどうなのか理解するため&見返し用に纏めたメモです。
前提
Google Chromeで値確認。この記事で使用する単語の定義は以下。
- ドキュメント
-
margin
,border
,padding
の設定がないHTMLHtmlElement
-
document.documentElement
の内容が上記であると見なす
-
- コンテンツ全体
HTMLBodyElement
-
document.body
の内容が上記であると見なす
- ビューポート
- ブラウザのドキュメント表示領域
- スクリーン
- モニターの表示領域
主な基準のサイズ
大体の関係図
確認用コード
code
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 10px;
border: solid;
border-width: 5px;
padding: 7px;
}
</style>
</head>
<body>
<button type="button" onclick="refresh()">refresh</button>
<h4>window</h4>
<ul>
<li>inner: <span id="wiw"></span> / <span id="wih"></span></li>
<li>outer: <span id="wow"></span> / <span id="woh"></span></li>
<li>scroll: <span id="wsw"></span> / <span id="wsh"></span></li>
</ul>
<h4>html</h4>
<ul>
<li>offset: <span id="how"></span> / <span id="hoh"></span></li>
<li>client: <span id="hcw"></span> / <span id="hch"></span></li>
<li>scroll: <span id="hsw"></span> / <span id="hsh"></span></li>
<li>bcrect: <span id="hgw"></span> / <span id="hgh"></span></li>
</ul>
<h4>body</h4>
<ul>
<li>offset: <span id="bow"></span> / <span id="boh"></span></li>
<li>client: <span id="bcw"></span> / <span id="bch"></span></li>
<li>scroll: <span id="bsw"></span> / <span id="bsh"></span></li>
<li>bcrect: <span id="bgw"></span> / <span id="bgh"></span></li>
</ul>
<ul>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest</li>
<ul>
<script>
function refresh() {
const rectHtml = document.documentElement.getBoundingClientRect();
const rectBody = document.body.getBoundingClientRect();
getDOM("wiw").textContent = window.innerWidth;
getDOM("wih").textContent = window.innerHeight;
getDOM("wow").textContent = window.outerWidth;
getDOM("woh").textContent = window.outerHeight;
getDOM("wsw").textContent = window.scrollX;
getDOM("wsh").textContent = window.scrollY;
getDOM("how").textContent = document.documentElement.offsetWidth;
getDOM("hoh").textContent = document.documentElement.offsetHeight;
getDOM("hcw").textContent = document.documentElement.clientWidth;
getDOM("hch").textContent = document.documentElement.clientHeight;
getDOM("hsw").textContent = document.documentElement.scrollWidth;
getDOM("hsh").textContent = document.documentElement.scrollHeight;
getDOM("hgw").textContent = rectHtml.width;
getDOM("hgh").textContent = rectHtml.height;
getDOM("bow").textContent = document.body.offsetWidth;
getDOM("boh").textContent = document.body.offsetHeight;
getDOM("bcw").textContent = document.body.clientWidth;
getDOM("bch").textContent = document.body.clientHeight;
getDOM("bsw").textContent = document.body.scrollWidth;
getDOM("bsh").textContent = document.body.scrollHeight;
getDOM("bgw").textContent = rectBody.width;
getDOM("bgh").textContent = rectBody.height;
}
function getDOM(id) {
return document.querySelector(`#${id}`);
}
</script>
</body>
</html>
ドキュメント
-
HTMLHtmlElement
インターフェース (document.documentElement
)- 以下のプロパティは整数に丸められた値が取得される
-
offsetWidth/Height
の小数点以下を含む値は簡単に取得可能-
.getBoundingClientRect().width/height
で取得
-
プロパティ | メモ |
---|---|
offsetWidth/Height |
overflow分を含まない全体のサイズ |
clientWidth/Height |
スクロールバーを含まないビューポートサイズ |
scrollWidth/Height |
全体のサイズ 最小値はclientWidth/Height
|
コンテンツ全体
-
HTMLBodyElement
インターフェース (document.body
)- 以下のプロパティは整数に丸められた値が取得される
-
offsetWidth/Height
の小数点以下を含む値は簡単に取得可能-
.getBoundingClientRect().width/height
で取得
-
プロパティ | メモ |
---|---|
offsetWidth/Height |
marginを含まない全体のサイズ |
clientWidth/Height |
marginとborderを含まない全体のサイズ |
scrollWidth/Height |
使用しないのが無難 (overflowを含むがmarginを含まない) |
ビューポート
-
Window
インターフェース (window
)
プロパティ | メモ |
---|---|
innerWidth/Height |
ビューポートのサイズ |
outerWidth/Height |
ブラウザのウィンドウサイズ |
scrollX/Y |
スクロールされた量 |
スクリーン
-
Screen
インターフェース (window.screen
)
プロパティ | メモ |
---|---|
width/height |
モニターの解像度のイメージ |
availWidth/Height |
タスクバー等を除いたモニターの表示領域 |
要素のサイズ
大体の関係図
確認用コード
code
<!DOCTYPE html>
<html>
<head>
<style>
#parent {
position: relative;
}
#main {
position: absolute;
left: 50px;
top: 50px;
margin: 10px;
border: solid;
border-width: 5px;
padding: 7px;
width: 250px;
height: 200px;
overflow: auto;
transform: rotate(var(--angle));
--angle: 0deg;
}
</style>
</head>
<body>
<button type="button" onclick="refresh()">refresh</button>
<button type="button" onclick="rotate()">rotate</button>
<h4>element</h4>
<ul>
<li>offset: <span id="offw"></span> / <span id="offh"></span></li>
<li>client: <span id="cliw"></span> / <span id="clih"></span></li>
<li>scroll: <span id="scrw"></span> / <span id="scrh"></span></li>
<li>bcrect: <span id="bcrw"></span> / <span id="bcrh"></span></li>
</ul>
<div id="parent">
<div id="main">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at laoreet magna.
Aliquam erat volutpat. Praesent molestie, dolor ut eleifend aliquam, mi ligula ultrices sapien, quis cursus
neque dui nec risus. Duis tincidunt lobortis purus eu aliquet. Quisque in dignissim magna. Aenean ac lorem at
velit ultrices consequat. Nulla luctus nisi ut libero cursus ultrices. Pellentesque nec dignissim enim. Phasellus
ut quam lacus, sed ultricies diam. Vestibulum convallis rutrum dolor, sit amet egestas velit scelerisque id.
Proin non dignissim nisl. testtesttesttesttesttesttesttesttest Sed mi odio, ullamcorper eget mattis id, malesuada vitae libero. Integer dolor lorem,
mattis sed dapibus a, faucibus id metus. Duis iaculis dictum pulvinar. In nisi nibh, dapibus ac blandit at, porta
at arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent
dictum ipsum aliquet erat eleifend sit amet sollicitudin felis tempus. Aliquam congue cursus venenatis. Maecenas
luctus pellentesque placerat. Mauris nisl odio, condimentum sed fringilla a, consectetur id ligula. Praesent sem
sem, aliquet non faucibus vitae, iaculis nec elit. Nullam volutpat, lectus et blandit bibendum, nulla lorem congue
turpis, ac pretium tortor sem ut nibh. Donec vel mi in ligula hendrerit sagittis. Donec faucibus viverra fermentum.
</div>
</div>
<script>
function refresh() {
const el = getDOM("main");
const rect = el.getBoundingClientRect();
getDOM("offw").textContent = el.offsetWidth;
getDOM("offh").textContent = el.offsetHeight;
getDOM("cliw").textContent = el.clientWidth;
getDOM("clih").textContent = el.clientHeight;
getDOM("scrw").textContent = el.scrollWidth;
getDOM("scrh").textContent = el.scrollHeight;
getDOM("bcrw").textContent = rect.width;
getDOM("bcrh").textContent = rect.height;
}
function getDOM(id) {
return document.querySelector(`#${id}`);
}
function rotate() {
const el = getDOM("main");
const current = getComputedStyle(el).getPropertyValue("--angle");
const angle = current === "0deg" ? "45deg" : current === "45deg" ? "90deg" : "0deg";
el.style.setProperty("--angle", angle);
}
</script>
</body>
</html>
各プロパティ
- 以下のプロパティは整数に丸められた値が取得される
- 通常時、
offsetWidth/Height
の小数点以下を含む値は簡単に取得可能-
.getBoundingClientRect().width/height
で取得
-
プロパティ | 所属 | メモ |
---|---|---|
offsetWidth/Height |
HTMLElement |
main+padding+border(+scrollbar) |
clientWidth/Height |
Element |
main+padding |
scrollWidth/Height |
Element |
overflowを含むmain+padding |
getBoundingClientRect
(DOMRect
)の違い
- CSSの
transform
後の状態が値に反映される-
offset
,client
,scroll
系プロパティは値が変化しない -
DOMRect
のみ値が変化する
-
要素の座標
大体の関係図
確認用コード
code
<!DOCTYPE html>
<html>
<head>
<style>
#parent {
position: relative;
}
#main {
position: absolute;
left: 50px;
top: 50px;
margin: 10px;
border: solid;
border-width: 5px;
padding: 7px;
width: 200px;
height: 200px;
overflow: auto;
}
</style>
</head>
<body>
<button type="button" onclick="refresh()">refresh</button>
<h4>element</h4>
<ul>
<li>offset: <span id="offl"></span> / <span id="offt"></span></li>
<li>client: <span id="clil"></span> / <span id="clit"></span></li>
<li>scroll: <span id="scrl"></span> / <span id="scrt"></span></li>
<li>bcrect: <span id="bcrl"></span> / <span id="bcrt"></span></li>
</ul>
<div id="parent">
<div id="main">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at laoreet magna.
Aliquam erat volutpat. Praesent molestie, dolor ut eleifend aliquam, mi ligula ultrices sapien, quis cursus
neque dui nec risus. Duis tincidunt lobortis purus eu aliquet. Quisque in dignissim magna. Aenean ac lorem at
velit ultrices consequat. Nulla luctus nisi ut libero cursus ultrices. Pellentesque nec dignissim enim. Phasellus
ut quam lacus, sed ultricies diam. Vestibulum convallis rutrum dolor, sit amet egestas velit scelerisque id.
Proin non dignissim nisl. testtesttesttesttesttesttesttesttest Sed mi odio, ullamcorper eget mattis id, malesuada vitae libero. Integer dolor lorem,
mattis sed dapibus a, faucibus id metus. Duis iaculis dictum pulvinar. In nisi nibh, dapibus ac blandit at, porta
at arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent
dictum ipsum aliquet erat eleifend sit amet sollicitudin felis tempus. Aliquam congue cursus venenatis. Maecenas
luctus pellentesque placerat. Mauris nisl odio, condimentum sed fringilla a, consectetur id ligula. Praesent sem
sem, aliquet non faucibus vitae, iaculis nec elit. Nullam volutpat, lectus et blandit bibendum, nulla lorem congue
turpis, ac pretium tortor sem ut nibh. Donec vel mi in ligula hendrerit sagittis. Donec faucibus viverra fermentum.
</div>
</div>
<script>
function refresh() {
const el = getDOM("main");
const rect = el.getBoundingClientRect();
getDOM("offl").textContent = el.offsetLeft;
getDOM("offt").textContent = el.offsetTop;
getDOM("clil").textContent = el.clientLeft;
getDOM("clit").textContent = el.clientTop;
getDOM("scrl").textContent = el.scrollLeft;
getDOM("scrt").textContent = el.scrollTop;
getDOM("bcrl").textContent = rect.left;
getDOM("bcrt").textContent = rect.top;
}
function getDOM(id) {
return document.querySelector(`#${id}`);
}
</script>
</body>
</html>
各プロパティ
-
clientLeft/Top
は整数に丸められた値が取得される -
el
は対象の要素を表す -
rect
はel.getBoundingClientRect()
のDOMRect
を表す
プロパティ | 原点 | 位置 | メモ |
---|---|---|---|
el.offsetLeft/Top |
el.offsetParent |
el border始点 |
親要素からの相対位置 |
el.clientLeft/Top |
el border始点 |
el padding始点 |
borderの幅 |
el.scrollLeft/Top |
el padding始点 |
表示領域始点 | スクロール幅 |
rect.left/top (rect.x/y ) |
ビューポート |
el border始点 |
ビューポートからの相対位置 |
ポインターの座標
大体の関係図
確認用コード
code
<!DOCTYPE html>
<html>
<head>
<style>
#parent {
margin: 50px;
border: solid;
border-width: 1px;
}
#main {
margin: 30px;
border: solid;
border-width: 5px;
padding: 7px;
width: 400px;
height: 300px;
}
</style>
</head>
<body>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<button type="button" onclick="start()">start</button>
<button type="button" onclick="startThrottle()">throttle</button>
<button type="button" onclick="end()">end</button>
<h4>element</h4>
<ul>
<li>offset: <span id="offx"></span> / <span id="offy"></span></li>
<li>client: <span id="clix"></span> / <span id="cliy"></span></li>
<li>screen: <span id="scrx"></span> / <span id="scry"></span></li>
<li>page: <span id="pgx"></span> / <span id="pgy"></span></li>
<li>mvmt: <span id="mvx"></span> / <span id="mvy"></span></li>
<li>manual: <span id="manx"></span> / <span id="many"></span></li>
</ul>
<div id="parent">
<div id="main">
</div>
</div>
<script>
const fnThrottle = throttle(100,update);
let prev = { x: 0, y: 0 };
function start() {
document.addEventListener("pointermove", update);
}
function startThrottle() {
document.addEventListener("pointermove", fnThrottle);
}
function end() {
document.removeEventListener("pointermove", update);
document.removeEventListener("pointermove", fnThrottle);
prev = { x: 0, y: 0 };
}
function updateThrottle(ev) {
}
function update(ev) {
getDOM("offx").textContent = ev.offsetX;
getDOM("offy").textContent = ev.offsetY;
getDOM("clix").textContent = ev.clientX;
getDOM("cliy").textContent = ev.clientY;
getDOM("scrx").textContent = ev.screenX;
getDOM("scry").textContent = ev.screenY;
getDOM("pgx").textContent = ev.pageX;
getDOM("pgy").textContent = ev.pageY;
getDOM("mvx").textContent = ev.movementX;
getDOM("mvy").textContent = ev.movementY;
const manual = calc(ev);
getDOM("manx").textContent = manual.x;
getDOM("many").textContent = manual.y;
}
function getDOM(id) {
return document.querySelector(`#${id}`);
}
function calc(ev) {
const ret = { x: ev.screenX-prev.x, y: ev.screenY-prev.y };
prev = { x: ev.screenX, y: ev.screenY };
return ret;
}
function throttle(interval, fn) {
let timer;
let last = 0;
const elapsed = () => Date.now() - last;
const run = (args) => {
fn.call(null, ...args);
last = Date.now();
};
return (...args) => {
if (!last) {
run(args);
return;
}
clearTimeout(timer);
timer = setTimeout(() => {
if (elapsed() >= interval) {
run(args);
}
}, interval - elapsed());
};
}
</script>
</body>
</html>
各プロパティ
-
PointerEvent
インターフェース
プロパティ | 原点 | 備考 |
---|---|---|
offsetX/Y |
直下要素 | 直下要素:document.elementFromPoint(ev.clientX,ev.clientY)
|
clientX/Y |
ビューポート | 相対位置のイメージ |
pageX/Y |
ドキュメント | 絶対位置のイメージ |
screenX/Y |
モニター | OSのAPIをブラウザがバイパスしているイメージ |
Discussion
PointerEvent の というよりも MouseEvent のではあるのですが movementX movementY 便利ですよね。
便利ですね!と言いたいのですが、私の用途ではmousemoveやpointermoveイベントは常にthrottlingさせているので使ったことがないのです・・・。
が、同じことを自分で計算することはあるので、もしかしたらthrottlingでも使えるかもと思い直し検証してみました。結果はダメでしたが良いきっかけになりました、ありがとうございます。
私のところだと、こういうドラッグ操作とかで使っています。