JavaScript | DOM 操作:要素の位置・サイズ・スクロール – ビューポートとは

JavaScript JavaScript
スポンサーリンク

ビューポートとは何か

ビューポートは「今、ユーザーに見えている画面の領域」です。ページ全体(ドキュメント)の中で、スクロールせずに表示されている矩形がビューポート。ここが重要です:JavaScriptで“画面サイズ”や“画面に対する位置”を扱うときは、常にビューポートを基準にします。スクロールやズーム、モバイルのUI(アドレスバーの出入り)により、ビューポートは変化します。


ビューポートのサイズを読む(基本の数値)

window.innerWidth / innerHeight(外側寄りの見える領域)

<script>
  console.log(window.innerWidth, window.innerHeight);
</script>
HTML

ここが重要です:innerWidth/innerHeight は“今見えている画面”の幅・高さを返します。モバイルではブラウザUIの表示状態で変わることがあり、動的に値が増減します。

document.documentElement.clientWidth / clientHeight(スクロールバー除外の見える領域)

<script>
  const w = document.documentElement.clientWidth;
  const h = document.documentElement.clientHeight;
  console.log(w, h);
</script>
HTML

ここが重要です:clientWidth/Height は内部スクロールバーの厚みを除いた“レイアウト計算に向いた”見える領域です。「収まるか」の判定やグリッド計算で安定します。


画面に対する位置・サイズの取得(rectの基礎)

getBoundingClientRect で画面座標を知る

<div id="box" style="width:160px; height:80px; border:1px solid #333"></div>
<script>
  const r = box.getBoundingClientRect();
  console.log(r.left, r.top, r.width, r.height); // 画面左上からの位置とサイズ(小数あり)
</script>
HTML

ここが重要です:rect は“ビューポート基準”の位置とサイズを返します。スクロールやズームが反映され、交差判定・ポップアップ位置合わせなど“画面目線”の処理で必須です。


モバイルの二種類のビューポート(レイアウト vs ビジュアル)

レイアウトビューポートとビジュアルビューポート

  • レイアウトビューポート:CSSレイアウトの基準。ズームやUIの出入りに対して比較的安定。
  • ビジュアルビューポート:実際に見えている領域。ピンチズームやアドレスバーの出入りでサイズが変わる。

ここが重要です:見え方に合わせたいなら“ビジュアル”、レイアウトの計算を崩したくないなら“レイアウト”。実装目的に応じて使い分けます。

VisualViewport API(高度な追従が必要な場合)

<script>
  if (window.visualViewport) {
    visualViewport.addEventListener("resize", () => {
      console.log(visualViewport.width, visualViewport.height, visualViewport.scale);
    });
    visualViewport.addEventListener("scroll", () => {
      console.log(visualViewport.offsetLeft, visualViewport.offsetTop);
    });
  }
</script>
HTML

ここが重要です:ピンチズーム時の表示崩れ対策や、HUDを画面の“見えている部分”に追従させたい場合に有効です。


CSSのビューポート単位と設定(vw/vh と meta)

vw / vh 単位(画面に対する割合)

.hero { width: 100vw; height: 100vh; }
CSS

ここが重要です:vw/vh はビューポートに対する割合。モバイルで“100vhが実際の見える高さとズレる”問題があり、最近は動的な単位(lvh/svh/dvh)が追加されています。対応環境なら dvh(動的高さ)を使うと“アドレスバー出入り”に追従します。

meta viewport(モバイルのレイアウト基準を決める)

<meta name="viewport" content="width=device-width, initial-scale=1">
HTML

ここが重要です:これを設定しないと、モバイルで“狭い画面をデスクトップ前提で縮小表示”され、タップやレイアウトが破綻します。必ず指定しましょう。


実践例(中央配置・可視判定・スクロール補正)

画面中央にモーダルを置く(transform補正)

<div id="modal" class="center">モーダル</div>
<style>
  .center {
    position: fixed; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    max-width: min(92vw, 640px);
    max-height: 84vh; overflow: auto;
    background: #fff; border: 1px solid #ccc; padding: 16px;
  }
</style>
HTML

ここが重要です:50%は“左上”を中央に運ぶので、translate(-50%, -50%)で“中心”に補正します。max-width/max-heightで画面に収め、コンテンツは内側スクロール。

要素が画面内に見えているかを判定

<script>
  function isInViewport(el, margin = 0) {
    const r = el.getBoundingClientRect();
    return r.bottom > -margin && r.top < window.innerHeight + margin &&
           r.right  > -margin && r.left < window.innerWidth  + margin;
  }
  console.log("見えている?", isInViewport(document.getElementById("box"), 50));
</script>
HTML

ここが重要です:rect と画面サイズ(innerWidth/Height)で“可視/不可視”判定。marginを設けると近接時に先読みできます。

固定ヘッダで隠れないスクロール位置の計算

<header style="position:sticky; top:0; height:64px"></header>
<section id="target" style="margin-top:1200px">目的地</section>
<script>
  function scrollToVisibleTop(el, header = 0) {
    const rect = el.getBoundingClientRect();
    const y = window.scrollY + rect.top - header;
    window.scrollTo({ top: Math.max(y, 0), behavior: "smooth" });
  }
  scrollToVisibleTop(target, 64);
</script>
HTML

ここが重要です:rect(画面基準)+現在のスクロール量で“ページ基準の座標”を作り、固定ヘッダ分を差し引くと、ちょうど見える位置に止まります。


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

100vh が実際の高さとズレる(モバイル)

アドレスバーの出入りで“見える高さ”が変わります。対策:可能なら dvh を使用、JSで innerHeight を読んで高さを上書き、もしくはコンテンツに余白を残してはみ出しを許容。

スクロールバーの厚みで計算がズレる

内側レイアウトは clientWidth/Height(バー除外)で、外側配置は offsetWidth/Height(バー込み)で扱います。目的に応じた値を選ぶとズレが消えます。

画面基準と親基準の混同

画面の中央や可視判定は“ビューポート基準”(rect/innerWidth/Height)。親内の位置合わせは“offsetParent基準”(offsetLeft/Top、clientWidth/Height)。基準を混ぜないことが計算の安定につながります。

ピンチズームへの非対応でHUDがズレる

視覚に追従するHUDなら VisualViewport を監視。対応が不要なら、過剰な追従を避けて“レイアウト基準”を優先し、要素には適切な余白とレスポンシブを与える。


まとめ

ビューポートは「今見えている画面領域」で、画面サイズは window.innerWidth/innerHeight、レイアウト計算向けには document.documentElement.clientWidth/Height、位置・サイズは getBoundingClientRect で取得します。モバイルではレイアウト/ビジュアルの二種類のビューポートを意識し、必要に応じて VisualViewport を使う。CSSでは vw/vh(可能なら dvh)と meta viewport で基準を整え、固定ヘッダやスクロールの補正は rect と現在のスクロール量の組み合わせで丁寧に対処。基準の選び分けを徹底すれば、初心者でもズレのない“画面目線”のUIレイアウトが安定して作れます。

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