スマホでサイトを確認したら、ファーストビューの下がスパッと見切れていた。パソコンでは完璧だったのに。
Web制作をしていると、一度は必ずぶつかるのが、この「100vh問題」です。画面の高さいっぱいにメインビジュアルを広げようとheight: 100vhを指定したのに、いざスマホで開くと、下に置いたボタンやスクロールを促す矢印が画面の外へ。CSSの書き方は何も間違っていないのに、です。犯人はあなたのコードではなく、スマホブラウザのアドレスバーにあります。
Web制作には長い間携わっていますが、この問題には本当に長いこと付き合わされてきました。JavaScriptで画面の高さを測ってCSSに書き戻す、いわゆる「vhハック」を何十回書いたか分かりません。
ところが今は、CSSを1行足すだけで終わります。この記事では、スマホで100vhが見切れる本当の原因と、CSSの新しい単位「svh・lvh・dvh」を使った解決法・使い分けを、コピペで使えるコード付きで解説します。
「svhとdvh、結局どっちを使えばいいの?」という疑問にも、実務目線ではっきり答えを出します。新単位の名前だけ聞いてなんとなくスルーしていた方も、これを機に手元のサイトを置き換えてみてください。数年前の自分に教えてあげたい内容です。
スマホで100vhが見切れる本当の原因
まず、犯人をはっきりさせておきましょう。
vhは「ビューポート(画面の表示領域)の高さの1%」を表す単位で、100vhなら画面の高さぴったりになるはず。実際、パソコンではその通りに動きます。
ところがスマホのブラウザには、スクロールに合わせて伸び縮みするアドレスバーがあります。ページを開いた直後はバーが表示されていて、下にスクロールするとスッと隠れる、あの動きです。
つまりスマホでは「画面の高さ」が2種類あるわけです。アドレスバーが出ている狭い状態と、隠れた広い状態。主要なスマホブラウザでは、100vhは「アドレスバーが隠れた広い状態」を基準に計算されるため、バーが出ている開いた直後の画面でははみ出してしまいます。
実はこれ、バグではなく仕様です。スクロールでアドレスバーが動くたびに100vhの中身まで伸び縮みしたら、ページ全体がガタガタ揺れて操作どころではなくなります。それを避けるために、ブラウザ側があえて基準を「広いほう」に固定しているんですね。
理屈は分かる。でも、作る側からすれば見切れるのは困る。この板挟みを解消するために生まれたのが、次に紹介する新しい単位です。
解決の切り札「svh・lvh・dvh」3つの新単位
100vh問題を解決するために、CSSにはビューポート単位の仲間が追加されました。名前は似ていますが、頭文字の意味さえ押さえれば迷いません。
svh:いちばん狭い状態が基準(本命はこれ)
svhのsはSmall。アドレスバーが表示された「いちばん狭い状態」の画面を基準にします。
100svhを指定すれば、アドレスバーが出ていても要素は画面内にすっぽり収まり、見切れは起きません。バーが隠れたときは下に少し余白ができますが、ボタンがはみ出すことに比べればかわいいものです。ファーストビューの見切れ対策なら、まずsvhを選んでおけば間違いありません。
lvh:いちばん広い状態が基準
lvhのlはLarge。アドレスバーが隠れた「いちばん広い状態」が基準で、実質的には従来のvhとほぼ同じ動きです。
「バーが隠れたときに画面いっぱいに広がってほしい」という演出向けで、出番は正直少なめ。vhの挙動を意図的に選んでいると明示したいときに使う、くらいの立ち位置です。
dvh:アドレスバーに合わせて動的に変わる
dvhのdはDynamic。アドレスバーが出ていれば狭く、隠れれば広くと、そのときどきの表示領域に合わせて値が変わります。
「常に今見えている高さぴったり」と聞くと万能に思えます。が、後述するとおり、これには分かりやすい落とし穴があります。
ちなみに高さのsvh・lvh・dvhに対応して、幅にもsvw・lvw・dvwという仲間がいます。考え方は同じなので、セットで覚えておくと得です。
関連記事:CSS :has()の使い方|親要素を選択できる注目の疑似クラスを初心者向けに解説
実務での使い分けとコピペできる書き方
ファーストビューはこの2行で決まり
結論のコードはこれだけです。そのままコピペで使えます。
.hero {
height: 100vh; /* 新単位が使えない古い環境向け */
height: 100svh; /* 対応ブラウザではこちらが優先される */
}
CSSは後に書いた指定が優先され、解釈できない値は無視される仕組みです。この順番で書いておけば、古い環境ではvh、対応ブラウザではsvhが効きます。フォールバックまで込みの鉄板の書き方です。
新単位はChrome 108以降・Safari 15.4以降・Firefox 101以降で使えます。2026年時点では、現役で使われているスマホならまず対応していると考えて大丈夫です。
ひとつ実務的な補足を。ファーストビューに載せる文字量が多いページでは、heightをmin-height: 100svhに変えておくと、中身が画面より大きくなったときにあふれず伸びてくれるので安全です。
dvhの落とし穴:スクロールでガタつく
「動的に追従するなら、dvhがいちばん賢いのでは?」と思った方、ちょっと待ってください。
dvhはアドレスバーが伸縮するたびに値が変わります。つまりスクロールのたびに要素の高さが変わり、レイアウトがガタつく原因になります。しかも値の更新はブラウザ側で間引かれるため、アニメーションのように滑らかには追従してくれません。
実は私も一度、ファーストビューに安易に100dvhを使って、スクロールするたびに背景画像がビクッと動く残念なページを作りかけたことがあります。dvhは、全画面モーダルやチャット画面のように「常に今の画面ぴったり」が必須のUIに絞って使うのがおすすめです。迷ったらsvh、が安全な合言葉です。
もうひとつ細かい注意点を。スマホで文字入力時に出る仮想キーボードは、ビューポート単位には影響しません。キーボードが出ても100svhや100dvhの値は変わらないので、入力欄まわりのレイアウトは実機で別途確認しておきましょう。
まとめ
スマホで100vhが見切れる原因と、新単位svh・lvh・dvhによる解決法を紹介してきました。
原因は、伸び縮みするアドレスバーに対して、100vhが「いちばん広い状態」を基準に計算されるという仕様でした。ファーストビューの見切れは、height: 100vhの下にheight: 100svhを1行足すだけでほぼ解決します。dvhは便利そうに見えて、スクロール時のガタつきという副作用があるので、全画面モーダルなど本当に必要な場面だけに使う。この使い分けさえ覚えれば十分です。
正直なところ、この単位が主要ブラウザすべてに行き渡ったときは、少し感動しました。JavaScriptで画面の高さを測り、リサイズのたびに書き換えて、それでも機種によって微妙にズレる。あの数年間の試行錯誤が、CSS1行で終わる時代になったんですから!
Webの標準は、現場の「困った」をちゃんと拾って進化しています。:has()やCSSのネストもそうですが、「昔は無理だったから」と思い込んで避けているものほど、今のCSSならあっさり書けたりします。数年前の常識のまま止まっているCSSの知識は、たまに棚卸しする価値がありますよ。
まずは手元のサイトのファーストビューに100svhを足すところから。スマホで開いた瞬間、ボタンがきちんと画面に収まっているのを確認できたときの安心感は、地味ですが確実に積み上がる品質です。