はじめに
ヘッダー、本文、フッターを持つ画面で、本文を画面高いっぱいまで広げたいことがあります。height: 100%を追加しても期待どおりに伸びず、フッターが本文の直後に表示されることがあります。
これはブラウザ固有の不具合ではありません。パーセント指定の高さは、基準となる親要素の高さが決まって初めて計算できるためです。この記事では、画面全体を埋めるレイアウトを、親の高さとビューポート高さを区別して直します。
結論
アプリケーション画面の最小の高さをビューポートに合わせたい場合は、外側の要素にmin-height: 100dvhを指定し、ヘッダー・本文・フッターの配置をGridで表します。本文は余った領域を受け取るため、内容が少なくてもフッターを下端へ置けます。
.app {
min-height: 100dvh;
display: grid;
grid-template-rows: auto 1fr auto;
}
なぜheight: 100%だけでは足りないのか
次の指定だけでは、.appの親であるbodyの高さが明示的・確定的でないため、100%の基準となる画面高を持てない場合があります。heightのパーセント値は、親要素(containing block)の高さを基準に計算されます。
.app {
height: 100%;
}
height: 100%は「画面の100%」ではなく「親要素の計算済みの高さの100%」です。親の高さが決まっていなければ、子要素も画面高を基準に伸びません。
最小再現と修正
<div class="app">
<header>管理画面</header>
<main>内容が少ない画面</main>
<footer>フッター</footer>
</div>
壊れた例では、本文が短いとフッターが上へ詰まります。
.app {
height: 100%;
}
修正版では、画面の最小高を確保し、中央の本文だけを伸縮させます。
.app {
min-height: 100dvh;
display: grid;
grid-template-rows: auto 1fr auto;
}
壊れた例と修正後の例は css-viewport-height-debug-lab で比較できます。
手順/理由/確認/異常時
手順
- 開発者ツールで
.app、body、htmlのComputedheightを順に確認します。 - 画面全体を埋める必要がある要素へ
min-height: 100dvhを指定します。 - ヘッダー・本文・フッターがあるなら、外側をGridにして
auto 1fr autoを指定します。 - 本文が長い場合も短い場合も確認します。
理由
height: 100dvhは要素の指定サイズをビューポート高に合わせる指定です。本文が画面より長くなる可能性があるアプリ画面では、内容があふれたり、要素内スクロールが必要になったりします。最低限の高さを確保するmin-heightなら、長い本文にも自然に伸びます。
なお、dvhはアドレスバーなどのブラウザーUIの表示・非表示に応じて変化するため、スクロール中にレイアウトが動くことがあります。表示中のUIに隠れないことを優先する画面ではsvh、UIが隠れた状態まで使い切ることを優先する画面ではlvhも候補になります。
確認
- 本文が1行でもフッターがビューポート下端に置かれる
- 本文が長いとき、ページ全体が自然に縦スクロールする
- 320px幅とPC幅で横スクロールが増えない
- モバイル端末でアドレスバーの表示・非表示が変わったとき、レイアウトの変化や主要な操作の隠れ方を確認する
- ノッチやホームインジケーターがある端末では、必要に応じて
env(safe-area-inset-*)を余白へ反映する
異常時
モーダルやサイドパネルの内部だけをスクロールしたい場合は、ページ全体の高さと内部領域の高さを分けて設計します。その場合でも、親の高さを決めないまま子へheight: 100%を連鎖させないことが重要です。
まとめ
height: 100%が効かないときは、親要素の高さを確認します。画面高を埋める目的なら、min-height: 100dvhとGridで領域の役割を表すと、短い画面と長い画面の両方で安定します。