JavaScript | DOM 操作:要素の位置・サイズ・スクロール – スクロール位置の取得

JavaScript JavaScript
スポンサーリンク

スクロール位置の取得とは何か

スクロール位置の取得は「今、ページや要素がどれだけスクロールされているか」を数値で読み取ることです。縦方向はどれだけ上から下へ動いたか(Top)、横方向は左から右へ動いたか(Left)を表します。ここが重要です:ページ全体と特定要素で取得方法が違い、さらに“画面に対する位置”を知りたい場合は別の取り方(rect)になります。目的に応じた正しい API を選ぶのがコツです。


ページ全体のスクロール位置を読む

基本(window.scrollY / scrollX)

<div style="height:2000px"></div>
<script>
  window.addEventListener("scroll", () => {
    console.log("縦:", window.scrollY, "横:", window.scrollX);
  }, { passive: true });
</script>
HTML

ここが重要です:window.scrollY/scrollX は「ビューポート上端がページ左上からどれだけ離れたか」を直接返します。最もシンプルで、現代ブラウザで広く使えます。

互換的な代替(pageYOffset / scrollingElement.scrollTop)

<script>
  const y = window.pageYOffset; // scrollY と同義
  const x = window.pageXOffset; // scrollX と同義

  // より汎用的に取りたいなら
  const root = document.scrollingElement || document.documentElement;
  const y2 = root.scrollTop;
  const x2 = root.scrollLeft;
</script>
HTML

ここが重要です:古い環境や特殊モードでは document.scrollingElement(通常は html)で読むのが堅牢です。pageYOffset も scrollY と同等に使えます。


特定の要素のスクロール位置を読む

要素内スクロール(element.scrollTop / scrollLeft)

<div id="panel" style="height:160px; overflow:auto; border:1px solid #ccc">
  <div style="height:800px"></div>
</div>
<script>
  panel.addEventListener("scroll", () => {
    console.log("縦:", panel.scrollTop, "横:", panel.scrollLeft);
  }, { passive: true });
</script>
HTML

ここが重要です:scrollTop/scrollLeft は“その要素の内側スクロール”の現在位置です。最大値は「必要量 − 見えている量」で決まり、縦なら scrollHeight − clientHeight、横なら scrollWidth − clientWidth が上限になります。

スクロール可能量と端の判定

<script>
  function canScrollDown(el) {
    return el.scrollTop < el.scrollHeight - el.clientHeight;
  }
  function canScrollRight(el) {
    return el.scrollLeft < el.scrollWidth - el.clientWidth;
  }
</script>
HTML

ここが重要です:端で無理にスクロールしても動かないため、事前に「まだ進めるか」を判定してボタン状態などを同期すると親切です。


画面に対する位置を知る(rect とスクロール併用)

要素の“画面座標”と“ページ座標”

<script>
  const r = target.getBoundingClientRect(); // 画面に対する位置とサイズ(小数あり)
  const pageTop = window.scrollY + r.top;   // ページ左上からの絶対位置
  const pageLeft = window.scrollX + r.left;
</script>
HTML

ここが重要です:getBoundingClientRect() は“ビューポート”基準です。ページの絶対座標が欲しい時は scrollY/scrollX を足し込みます。固定ヘッダの重なり補正もこの組み合わせで行います。


実践例(進捗バー、下端判定、スクロール方向検知、保存と復元)

ページ進捗バーの更新

<div id="bar" style="position:fixed;top:0;left:0;height:3px;background:#09f;width:0"></div>
<script>
  function updateBar() {
    const h = document.documentElement.scrollHeight;
    const vh = document.documentElement.clientHeight;
    const max = Math.max(h - vh, 1);
    const w = Math.min(window.scrollY / max, 1) * 100;
    bar.style.width = w + "%";
  }
  window.addEventListener("scroll", () => requestAnimationFrame(updateBar), { passive: true });
  updateBar();
</script>
HTML

ここが重要です:“最大量 − 見えている量”で正しく割り、rAF 内で描画更新すると滑らかで正確な進捗になります。

無限スクロールの下端近接判定

<script>
  function nearBottom(px = 200) {
    const root = document.scrollingElement || document.documentElement;
    return root.scrollTop + root.clientHeight > root.scrollHeight - px;
  }
  window.addEventListener("scroll", () => {
    if (nearBottom()) {
      // 追加読み込み処理
    }
  }, { passive: true });
</script>
HTML

ここが重要です:clientHeight(見えている高さ)と scrollHeight(必要高さ)で“あとどれくらいか”を判定します。余白 px を設けると体験が自然になります。

スクロール方向の検知(上向き/下向き)

<script>
  let lastY = window.scrollY;
  function onScroll() {
    const y = window.scrollY;
    const dir = y > lastY ? "down" : y < lastY ? "up" : "none";
    lastY = y;
    console.log("方向:", dir);
  }
  window.addEventListener("scroll", onScroll, { passive: true });
</script>
HTML

ここが重要です:前回値と比較するだけで方向が判断できます。ヘッダ表示/非表示の切替などに活用できます。

スクロール位置の保存と復元

<script>
  // 保存
  window.addEventListener("scroll", () => {
    sessionStorage.setItem("scrollY", String(window.scrollY));
  }, { passive: true });

  // 復元
  window.addEventListener("load", () => {
    const y = Number(sessionStorage.getItem("scrollY") || 0);
    window.scrollTo({ top: y, behavior: "instant" });
  });
</script>
HTML

ここが重要です:ページ再表示時に位置を戻すだけで再学習の負担を減らせます。復元はレイアウト確定後(load)に行うとズレが起きにくいです。


設計の勘所(どの値を使うか、性能、アクセシビリティ)

値の選び分けを明確にする

“ページ全体”は window.scrollY/scrollX(または scrollingElement.scrollTop/Left)、“要素内”は element.scrollTop/Left、“画面に対しての位置”は rect(+scrollY/scrollXで絶対座標へ)。ここが重要です:何を基準にしたいか(ページか要素か画面か)を先に決めると、迷いとズレが減ります。

性能を守る

スクロールは高頻度で発火します。処理は軽くし、描画更新は requestAnimationFrame にまとめ、監視は { passive: true } を付けます。ここが重要です:間引き(throttle)や状態の単一情報源(進捗バーなどは1箇所で更新)を徹底すると体感が安定します。

アクセシビリティに配慮する

スクロール後に目的要素へ focus() を当てるとキーボード操作にも優しくなります。固定ヘッダがある場合はヘッダ分を差し引いて停止位置を設計し、視差やアニメ軽減設定が有効な環境ではスムーズスクロールを避ける選択肢も検討します。ここが重要です:見え方だけでなく操作性も合わせると、使いやすさが大きく向上します。


よくある落とし穴と回避策

固定ヘッダの重なりで“目的地が隠れる”問題は、rect.top に scrollY を足し、ヘッダ高を差し引いて座標を求めることで解消できます。ページと要素の値を混同するとズレるため、window.scrollY と element.scrollTop の“基準の違い”を常に意識します。scrollHeight/clientHeight の“最大量 − 見えている量”の引き忘れは進捗が 100% に届かない典型エラーです。さらに、display: none の要素はレイアウト計算されず値が 0 になるため、計測時は visibility: hidden など“レイアウト参加状態”で測るのが安全です。


まとめ

スクロール位置は、ページなら window.scrollY/scrollX(または scrollingElement.scrollTop/Left)、要素なら element.scrollTop/Left、画面基準なら rect(+scrollY/scrollX)で取得します。進捗や端判定は scrollHeight/clientHeight(横は scrollWidth/clientWidth)と組み合わせるのが鉄則。固定ヘッダの補正や方向検知、保存・復元まで整えると、滑らかで正確なスクロール体験が作れます。処理は軽く、rAF と passive を活用し、基準の選択を明確にすれば、初心者でもズレのない堅実な実装ができます。

タイトルとURLをコピーしました