スマホで100vhが画面高さいっぱいにならない時の対処法

css

はじめに

こんにちは
株式会社TOKOSのエンジニアのたくやです
今回は、スマホで100vhが画面高さいっぱいにならない時の対処法をご紹介します。

今回は下記2つの方法をご紹介します。

dvhを使う(注意事項あり)
カスタムプロパティ + Javascriptを使う

プロジェクトに合わせて使い分けてください!

環境

動作確認環境は iOS safari バージョン16.5 です。
リセットCSSを使用しています。normalize.css です。
環境によっては多少スタイルが崩れる可能性があるため、十分に注意が必要です。

vh,dvhについて

画面高さいっぱいを、100vhで実装した時の問題

画面の高さいっぱいのメインビジュアルなどの要素を作る時、height:100vh を指定していませんか?
そうすると、PCでは問題ないのにスマホでは高さが合わず上手にいかないです。

原因は、スマホだとツールバーやアドレスバーといった動的バーが存在するため、画面高さが常に一定ではないからです。

100vhについて

画面高さいっぱいを実現する時、height: 100vh; をよく使いますが、
その 100vh は画面いっぱいの高さではなく、厳密には動的バーが表示されていない時の高さです。

そのため、動的バーが表示されている時(ページを上方向にスクロールした時など)には画面高さいっぱいになっていないのです。

その他のvhについて

私も最近まで知らなかったのですが、
vhには他に似たようなモノが存在します。

  • svh
    動的バーが表示されている状態の画面高さの1%
  • lvh
    動的バーが表示されていない状態の画面高さの1%
  • dvh
    動的バーの表示非表示を考慮した画面高さの1%
    簡単に言うと、svhとlvhを出し分けてくれるものです。

これら以外にもあるそうですが今回の説明は3つまでにします。(画面横方向のvwも同じようにあります。)

dvhを使えばで常に画面高さいっぱいを実現できそうです。

実装

dvhで実装してみる

dvhを使用してスマホで画面高さいっぱいを実装方法を、vhの場合と併せて説明します。

<div class="spacer"></div>
<div class="box --vh"> <!-- 100vhを指定する要素 -->
  <div class="item --top">90%</div>
  <div class="item --bottom">10%</div>
</div>
<div class="spacer"></div>
<div class="box --dvh"> <!-- 100dvhを指定する要素 -->
  <div class="item --top">90%</div>
  <div class="item --bottom">10%</div>
</div>
.box {
  color: #fff;
  font-size: 32px;
}

/* 100vhを指定する要素 */
.box.--vh {
  align-items: center;
  height: 100vh;
}

/* 100dvhを指定する要素 */
.box.--dvh {
  height: 100dvh;
}

.item {
  align-items: center;
  display: flex;
  justify-content: center;
}

.item.--top {
  background-color: #34d276;
  height: 90%;
}

.item.--bottom {
  background-color: #2cb5b9;
  height: 10%;
}

.spacer {
  background-color: #e4e4e4;
  height: 500px;
}

100vhの場合

100vhの場合、動的バーが表示されていると高さいっぱいになってくれていないことがわかります。

100dvhの場合

反対に、100dvhの場合だと動的バーが表示されていても高さいっぱいになってくれています。

dvhを使えば簡単に実装できましたね!
ですが、dvhにも大きな問題点があります。。。

対応しているブラウザが少ない

なんとdvh ですが、対応しているブラウザが全くもって少ないです。
iOS safariの場合16.4以降のみ対応のため、実用レベルになるまで少し時間がかかりそうです。

カスタムプロパティ + Javascriptを使う

dvhはまだ実用レベルではないため、別の方法をご紹介します。
CSSのカスタムプロパティとJavascriptを使用する方法です。

<div class="spacer"></div>
<!-- カスタムプロパティ + Javascript -->
<div class="box --dvh">
  <div class="item --top">90dvh</div>
  <div class="item --bottom">10dvh</div>
</div>
<div class="spacer"></div>
.box {
  color: #fff;
  font-size: 32px;
}

/* カスタムプロパティ + Javascript */
.box.--custom {
  height: 100vh; /* フォールバック */
  height: calc(var(--custom, 1vh) * 100);
}

.item {
  align-items: center;
  display: flex;
  justify-content: center;
}

.item.--top {
  background-color: #34d276;
  height: 90%;
}

.item.--bottom {
  background-color: #2cb5b9;
  height: 10%;
}

.spacer {
  background-color: #e4e4e4;
  height: 500px;
}
const setCustomHeight = () => {
  const customVhElement = document.getElementById("custom"); // 対象の要素を取得
  const customVh = window.innerHeight * 0.01; // 画面高さを所得
  customVhElement.style.setProperty("--custom", `${customVh}px`); //カスタムプロパティに値を入れる
};

// 画面にリサイズがあった時に処理を実行
window.addEventListener("resize", setCustomHeight);

// 処理の初期実行
setCustomHeight();

画面がリサイズされる度に、関数を呼んでいます。
その関数は、 画面高さを計算し、 —custom という カスタムプロパティに対してその計算した値を入れてくれます。
これで、動的バーが表示されても要素の高さがそれに応じて変化してくれるため、
画面高さいっぱいが実現できます。

ブラウザやデバイスの差異を気にする必要はありません。

さいごに

今回は、スマホで100vhが画面高さいっぱいにならない時の対処法について紹介しました。
①dvhを使う方法と、②カスタムプロパティ + Javascriptを使うの2種類の方法をご紹介しました。
①は現時点では使えるブラウザが限られているため、②の方法を使うのが良いですね!

おまけとして、、、CSSの学習にはこちらの書籍がおすすめです!

今回の内容にもあった、viewmortや高さ関わるCSSについて詳しく記載されています!
ぜひ読んでみてください!