全画面表示の高さは100vhで大丈夫?

コーディングデザインのフロントエンドHTML&CSSデベロッパー森です。
軽く実装出来ると思いきやなかなか悩ましい全画面表示の話です。

Webページの最上部は訪問者にインパクトを残すために背景に動画や画像を入れて全画面表示にすることがあります。
この表現を実現する方法はいくつもあります。

  1. html, body, 対象の要素の高さをすべて100%にする
  2. 対象の要素の高さを100vhにする
  3. min-height: -webkit-fill-available; を使う
  4. JavaScriptでウインドウの高さを測って対象の要素に高さ設定

基本的にはどの方法で実装するのも良さそうです。
ぱっと対応するのによさそうなのは「2. 対象の要素の高さを100vhにする」だな〜と思うところです。
実装が適切だと判断するポイントは下記の通り。

  • 初期表示で画面の高さと画像の高さが合う
  • ポートレートとランドスケープの切り替えでも画面の高さと画像の高さが合う
  • スクロール時に画像の大きさが変わらない

実装してみたところで下記の気になるポイントがありました。

  1. 表示は完璧。対象の要素以外にも余計にスタイルをつけるのが気になる
  2. iOS Safari/Chrome, Android Chromeだとファーストビューで表示するときに表示領域よりも高さが大きい状態になる
  3. Android ChromeとWin/Mac Chromeだとスタイルが反映されない
  4. iPhoneのランドスケープ表示だけ画像がはみ出す

それぞれを以下で確認してみます。HTMLとCSSのベースは下記のとおりです。

・HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>全画面表示</title>
  <link href="https://unpkg.com/sanitize.css" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="mv">メインヴィジュアル</div>
  <div class="content">メインヴィジュアルの下のコンテンツ</div>
</body>
</html>

・CSS

@charset "UTF-8";
.mv {
  background: url(animals.jpg) no-repeat center center; /* 画像は適当なものを使ってください */
  background-size: cover;
  color: #ffffff;
}
.content {
  height: 500px;
}

下記はiPhoneのOK表示とNG表示です。

・OK表示

・NG表示(下が隠れている&拡大している)

下記はAndroidのOK表示とNG表示です。

・OK表示

・NG表示(下が隠れている&拡大している)

html, body, 対象の要素の高さをすべて100%にする

CSSに下記を追加します。

html,
body,
.mv {
  height: 100%;
}

表示に問題はありませんが、対象の要素(.mv)以外にもスタイルを設定するのが面倒です。
対象の要素がbody直下になければ各階層の要素にもheight: 100%;を指定する必要があります。

表示自体は完璧でした。
✅初期表示で画面の高さと画像の高さが合う
✅ポートレートとランドスケープの切り替えでも画面の高さと画像の高さが合う
✅スクロール時に画像の大きさが変わらない

とはいえなるべく対象の要素へのスタイル指定で完結したいところ。
ということでいったんコメントアウトして次へ。

対象の要素の高さを100vhにする

CSSに下記を追加します。

.mv { height: 100vh; }

単純にこれで済めばよかったのですが、iOS Safari/Chrome, Android Chromeはファーストビューで表示するときに表示領域よりも高さが大きい状態になります。
これはファーストビューの上部にアドレバー、下部にツールバーが表示されるために表示領域は小さくなるのだけど、それらの高さを含んだ形で100vhを表示するためです。スクロールするとどちらも消えますもんね。。

表示は残念。
 初期表示で画面の高さと画像の高さが合う(モバイルで画面をはみ出す)
 ポートレートとランドスケープの切り替えでも画面の高さと画像の高さが合う(モバイルで画面をはみ出す)
✅スクロール時に画像の大きさが変わらない

想定した表示ではないためコメントアウトして次へ。

min-height: -webkit-fill-available; を使う

CSSに下記を追加します。

.mv {
  height: 100vh;
  height: -webkit-fill-available;
}

海外の記事を見ていたら福音のように飛び込んできた-webkit-fill-available
Chrome, Safari以外は100vhが適用されるので問題なし。
Safariは-webkit-fill-availableが適用されて問題なし。iOSのChromeはレンダリングエンジンがSafariなので問題なし。
そして問題はAndroid ChromeとWin/Mac Chrome。開発ツール上は有効な値と判定されるにも関わらずスタイルが反映されません。
惜しい。

表示は残念。
 初期表示で画面の高さと画像の高さが合う(Chromeで全画面表示にならない)
 ポートレートとランドスケープの切り替えでも画面の高さと画像の高さが合う(Chromeで全画面表示にならない)
 スクロール時に画像の大きさが変わらない(Chromeで全画面表示にならない)

想定した表示ではないためコメントアウトして次へ。

JavaScriptでウインドウの高さを測って対象の要素に高さ設定

HTMLの</body>の直前に下記を追加します。

  <script>
    document.querySelector('.mv').style.height = window.innerHeight + "px";
  </script>

初期表示はOK。ポートレートとランドスケープの切り替えはイベントで調整が必要で、

表示は残念。
✅初期表示で画面の高さと画像の高さが合う
 ポートレートとランドスケープの切り替えでも画面の高さと画像の高さが合う(イベントで調整が必要)
✅スクロール時に画像の大きさが変わらない

悩ましいな…と思いつつ下記のように調整してみました。
上記のscript要素はコメントアウトして、HTMLの</body>の直前に下記を追加します。

  <script>
    function adjustHeight() {
      document.querySelector('.mv').style.height = window.innerHeight + "px";
    };
    adjustHeight();
    window.addEventListener('orientationchange', function () {
      let afterOrientationChange = function() {
        adjustHeight();
        window.removeEventListener('resize', afterOrientationChange);
      };
      window.addEventListener('resize', afterOrientationChange);
    });
  </script>

iPhoneのランドスケープ表示だけ画像がはみ出してしまいます(iPadは大丈夫…謎)。
そんなにランドスケープで見る人が多くないことを期待してこれにて検証は終了です。

まとめ

完璧な表示なら CSSで height: 100%; を使う。
iPhoneのランドスケープ表示がよろしくないのを許容するなら JavaScriptで対応。

2020年6月25日CSS