はじめに
レスポンシブデザインを意識したレイアウトを作るとき、vh(viewport height)を使った指定をよく見かけます。
たとえば、
.main-visual {
height: 100vh;
}
このように書くと「画面の高さにピッタリ合わせる」レイアウトが簡単に実現できるため、特にファーストビューや全画面表示のセクションで重宝されます。
しかし、実際の運用やモバイル環境では、このvhが思わぬレイアウト崩れや余白ズレの原因になることがあります。
この記事では、vhの使い方から、具体的な弊害、そしてそれを回避する代替策まで解説します。
vhの使い方
まずはvhの基本をおさらいします。
-
1vh= ビューポート(表示領域)の高さの1% -
100vh= 画面の高さと同じ
たとえば、以下のように使えば「画面いっぱいに表示する要素」を簡単に作れます。
<body>
<section class="hero">hero</section>
</body>
.hero {
height: 100vh;
background: linear-gradient(135deg, #00bcd4, #2196f3);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 2rem;
}
これだけで、ウィンドウサイズにフィットするセクションが完成します。
PCのブラウザでは期待通りに動作することが多いため、「これでOK」と思いがちですが、問題はスマートフォンのブラウザにあります。
vhの弊害
1. スマホブラウザのUIが高さに含まれてしまう
スマートフォンのブラウザには、上下にアドレスバーやナビゲーションバーが存在します。
しかし100vhはそれらのUI部分を含めた高さで計算される場合があります。
そのため、以下のような問題が発生します:
- 画面下に意図しない余白が出る
- スクロールすると高さが変わる(バーが消える・出るたびに
vhが再計算される) - スクロール時にレイアウトがガクつく
特にSafariやChromeのモバイル版で頻発します。
2. iOS Safariの挙動が不安定
iOS Safariでは、ビューポートの高さが
- ページ読み込み直後
- スクロール時
で異なる値を返すことがあります。
たとえば、読み込み直後はアドレスバーが表示されていて短い状態、スクロールしてバーが消えると長い状態になります。
結果、100vhを指定していると要素の高さが勝手に伸び縮みし、見た目がズレてしまいます。
3. キーボード表示時の崩れ
フォーム要素があるページで、ユーザーがキーボードを表示した瞬間も問題です。
キーボードが画面の一部を占有するため、vhで指定した領域がはみ出してスクロールが発生することがあります。
代替策
代表的な代替策を紹介します。
100dvh(Dynamic Viewport Height)
2023年頃からサポートが広がっている新しい単位です。
.hero {
height: 100dvh;
}
dvhは「動的に変化するビューポートの高さ」を意味し、ブラウザUIの表示・非表示に合わせて正しい高さを反映してくれます。
最後に
vhはとても便利な単位ですが、スマートフォンのUIや挙動によって思わぬバグの温床になることがあります。
2025年現在は、dvhなどの新しいビューポート単位が登場しており、
多くの問題が解決されています。
