📏

iOS 15.4で追加されたCSS単位「dvh」が高さ100%問題を解決する

2022/03/25に公開
3

iOS 15.4でSafariに様々なアップデートがありましたが dvh という単位が追加されたことがWeb開発において大きな意味を持ちます。

これまでiOS Safariではスクロールを始めるとURLバーが小さくなり画面のサイズが変わるという問題がありました。
そのため高さ100%を「URLバーが大きい状態」と「URLバーが小さい状態」のどちらかで設定する必要があり、現在のURLバーの状態を反映した高さ100%をCSSだけで実現することは難しかったのです。
これを解決するのが dvh です。

結論

これまで height: 100%;height: 100vh; と記述していた部分を height: 100dvh; と記述すればOK

これまでの解決策

これまでiOS Safariで高さ100%を実現するためにはいくつかのパターンがありました。

パターン1: 100%

パーセントで指定するパターンです。
ただしこの場合は高さ100%にしたい要素がHTMLタグで下層にある場合、すべての要素に100%を記述する必要があるという面倒な方法でした。
vh 単位が誕生する前の古の方法でもあります。

この場合は、URLバーの状態を反映した高さ100%が実現出来ますが <html> タグまで height: 100%; を伝播していくのは大変です。

<!DOCTYPE html>
<html style="height: 100%">
  <body style="margin: 0; color: white; font-family: sans-serif; height: 100%">
    <div style="height: 100%">
      <div
        style="
          height: 100%;
          background-color: gray;
          display: flex;
          justify-content: center;
          align-items: center;
        "
      >
        <div>Center</div>
      </div>
      <div style="height: 100%; background-color: black; text-align: center">
        <div>Test</div>
      </div>
    </div>
  </body>
</html>

パターン2: 100vh

CSS3で vh 単位が登場して以降はこれを使用することが一般的になりました。
高さの伝播が必要ないことが最大の特徴です。

ただし、高さは「URLバーが小さい状態」の高さに固定されてしまいます。

コンテナの高さが大きいので縦の中央寄せも上手く機能しません。

<!DOCTYPE html>
<html>
  <body style="margin: 0; color: white; font-family: sans-serif">
    <div>
      <div
        style="
          height: 100vh;
          background-color: gray;
          display: flex;
          justify-content: center;
          align-items: center;
        "
      >
        <div>Center</div>
      </div>
      <div style="height: 100vh; background-color: black; text-align: center">
        <div>Test</div>
      </div>
    </div>
  </body>
</html>

(パターン3: JavaScript)

今回はCSSだけで実装することを前提にしていますが、JavaScriptを使用すればこれまでも、URLバーの状態を反映した高さ100%を実現することはできました。

しかしながら、簡単な表示の制御をするためだけにJavaScriptを書くことは面倒でした。

新しい解決策

新しい解決策である dvh タグは、これまで vh タグを使用していた場所をそのまま置き換えるだけで自動的にURLバーの状態を反映した高さ100%になります。

<!DOCTYPE html>
<html>
  <body style="margin: 0; color: white; font-family: sans-serif">
    <div>
      <div
        style="
          height: 100dvh;
          background-color: gray;
          display: flex;
          justify-content: center;
          align-items: center;
        "
      >
        <div>Center</div>
      </div>
      <div style="height: 100dvh; background-color: black; text-align: center">
        <div>Test</div>
      </div>
    </div>
  </body>
</html>

最高です!🙌

これからは vh ではなく dvh を使っていきましょう。

注意点

dvh はまだ実装が広まっていない新しい単位です。Safari 15.4以外の環境ではGoogle Chromeですら実装していません。ですので必ずフォールバックとセットで使用しましょう。

後に記述したCSSが優先される特徴を利用して以下のように記述すれば多くの場面に対応することができます。

<div style="height: 100vh; height: 100dvh"></div>

Discussion

FF

この日を待っていました!!
一つお伺いしたいのですが、dvhは活用法が思いつきますが、svh, lvhに関しては活用法が思いつきません。現時点でFutaさんが考えているsvh, lvhの具体的な活用法があればお伺いしたいです。

Futa OgawaFuta Ogawa

コメントありがとうございます!

svh, lvh は使いどころが難しいですよね。

例えば、必ず「URLバーが大きい状態」の高さが欲しいときに現状では vh を使っています。
しかしながら、URLバーの扱いは標準化された仕様で決まっていないので、Safariの現在のバージョンではそう実装されているというだけで将来のバージョンやAndroid Chromeなど別ブラウザでは、変わる可能性があります。

svh, lvh を使うことで、環境によらない安定したコードを書くことができるのではないでしょうか。

そもそもの使用場面については、はてブのコメントに以下のようなものがありました。

私はあり得る最大の高さを得るために100vhを使っているので、局面によって実際の値が変わるdvhでは意味が変わってしまう。つまり2つは分けないといけないのよ。

Shota TamuraShota Tamura

Ogawaさん

良い情報をありがとうございます。早速仕事で活用しております。

Fさん

外野からすみません。
svhを早速活用した場面の例として、Webサイトのトップセクションで、画像を画面いっぱいに表示したい、という例がありました。要件としては以下のような感じです。

  • スクロールを全くしていないときに、表示範囲いっぱいに画像を表示したい
  • かつ、スクロールを開始したときに、その範囲の高さが変わってほしくない(object-fit: coverで画像を表示していたりすると、不自然にリサイズされて見栄えが悪いため)

いままではJSでこねくり回していたので、楽ですねー✨