📱

CSSのsvh・dvhが全ブラウザ対応。iOS・Androidの画面いっぱいに要素を広げる最適解

2022/11/30に公開

iOS SafariやAndroid Chromeの画面の高さいっぱいにヒーローイメージを表示するという表現は、よく見かけます。

高さをいっぱいに広げるのに100vhを使うと、不要なスクロールが発生し、意図通りに表示されません。 この問題を解決するために、特殊なCSSを使ったりJSを使ったりと、開発の現場では多くの苦労がありました。

本日(2022/11/30)リリースされたGoogle Chrome 108で対応したsvhを使えば、手軽に画面いっぱいのヒーローイメージを作れます。

.hero-image {
  height: 100svh;
}

Safari・Firefoxでは対応済み、Chromeと中身が同じEdgeは12/1週リリースの108で対応するので、全ブラウザで使える時代が来ます。もちろん、iOS・Androidも対応です。

本記事では、svhの使い方、同様に使えるようになったdvhsvmaxなどの違い、従来の手法のデメリットをデモを交えて紹介します。

svhを使ったデモ

次のようなコンテンツを作ってみましょう。ページにアクセス時、ヒーローイメージがブラウザの高さいっぱいに広がり、スクロールすると後続コンテンツが見えるようなものです。

HTML コードは次のとおりです。

<main>
  <!-- ヒーローイメージ -->
  <div class="hero-image">
    <img src="ヒーローイメージ用画像" />
  </div>
  <section>
    <h1>ABOUT</h1>
    <!-- 以下、後続コンテンツ -->
  </section>
</main>

ヒーローイメージは.hero-image要素ですが、CSSで行うことはheight: 100svh;を指定するだけです。

.hero-image {
  height: 100svh;
}

iOS Safari、Android・デスクトップのChromeを始め、各環境で動作します。

▼ iOS Safariでの動作結果

▼ Android Chromeでの動作結果

▼ デスクトップのChromeでの動作結果

デモは次から確認できます。

https://codepen.io/pen/debug/NWzBBNB

svhとは

従来使われてきたvhvwとは、ビューポートに対する高さや幅を指します。

デスクトップブラウザのようなビューポートのサイズが固定のものでは十分だったのですが、iOS Safariなどではビューポートのサイズが可変になります。

このうち、ビューポートの高さが最小になった場合の高さを示すのがsvhというわけです。

ビューポートが大きい場合の高さを取得したい場合は、lvhを使います。

また、ビューポートの大きさが変わったときの高さを取得したい場合は、dvhを使います。100dvhを今回のメインビジュアル表現に使ってしまうと、スクロール時にメインビジュアルの高さが変わってしまうため、向いていません。100dvhは、全画面に表示するモーダルウインドウやナビゲーションを作る際に役立つでしょう。

その他の単位については後述します。

なぜ100vh100%-webkit-fill-availableでは駄目なのか?

今回作った表現は、100vh100%では駄目なのかと思う人もいるでしょう。従来の表現を100svhと比べてみましょう。

100vhだと はみ出る

次のように100vhを指定したとします。

.hero-image {
  height: 100vh;
}

この場合、ヒーローイメージ部分(.hero-image)はファーストビューからはみ出します。iOS Safariの場合、100vh100lvhと同じ高さになり、大きいビューポートの高さを取ってしまうのです。

ヒーローイメージがはみ出しているので、スクロールしてもヒーローイメージ部分が続いてしまいます。

たまに勘違いされますが、ビューポートの大きさが変わるのはiOSだけではありません。AndroidのChromeでも、同様にビューポートの大きさが変わるため、100vhでははみ出ます。

▼ Android Chromeで100vhを指定した結果

100%は煩雑

次のように100%を指定したとします。

.hero-image {
  height: 100%;
}

HTMLは次のようになっていることに注意してください。

<main>
  <!-- ヒーローイメージ -->
  <div class="hero-image">
    <img src="ヒーローイメージ用画像" />
  </div>
  <section>
    <h1>ABOUT</h1>
    <!-- 以下、後続コンテンツ -->
  </section>
</main>

この場合、ヒーローイメージ部分(.hero-image)はファーストビューの高さに足りません。

理由はヒーローイメージ部分(.hero-image)が外側のmain要素の高さいっぱいまでしか広がらないためです。

問題を解決するためには、祖先要素すべてに100%を設定する必要があります。煩雑ですし、ヒーローイメージ部分(.hero-image)の事情だけのためにhtmlbodyheight: 100%を指定するのはあまりよろしくないでしょう。

/* 祖先要素すべてへ高さ指定 */
html,
body,
main {
  height: 100%;
}

.hero-image {
  height: 100%;
}

-webkit-fill-availableは癖が強い

次のように-webkit-fill-availableを指定する方法もありました。

.hero-image {
  height: -webkit-fill-available;
}

この方法では確かにヒーローイメージ部分(.hero-image)はファーストビューの高さになりますし、祖先要素への高さ指定も不要です。

「デバイスの向きを変えたときに高さを再計算してくれない」という記事も稀に見かけますが、今現在のiOS Safariでは解消されています。

本手法の欠点の1つ目は、ChromeやFirefoxに対応していないことです。次のように処理を分岐する必要がありました。

.hero-image {
  height: 100vh;
}

@supports (-webkit-touch-callout: none) {
  .hero-image {
    height: -webkit-fill-available;
  }
}

欠点の2つ目は、「高さ50%」のような指定ができないことです。ビューポートの50%にヒーローイメージを広げたいみたいな表現のときに不便です。

▼ 動作しません

.hero-image {
  height: calc(-webkit-fill-available * 0.5);
}

JavaScriptを使う手法もありますが、いずれもsvhの便利さには適いません。

他にもいろいろな単位が使えるようになった

svhlvhdvh以外にも、さまざまな単位が使えるようになりました。

vmaxvminについて

以前からvmaxvminという単位が使えました。おさらいしておくと、次のとおりです。

  • vmax: ビューポートのうち、幅か高さの大きい方
  • vmin: ビューポートのうち、幅か高さの小さい方

sv*dv*と組み合わせられるので、svmaxlvminといった単位が使えるようになります。

vivbについて

論理的プロパティ(CSS Logical Properties)」に応じたvivbにも対応しました。

  • vi:インライン方向
  • vb:ブロック方向

sv*dv*と組み合わせられるので、svilvbといった単位が使えるようになります。

ビューポート単位のチートシート

以上をまとめると、次のようにして各ビューポートのサイズを作成できます。

  • ビューポートのサイズは?
    • 小さい方: svから始まる
    • 大きい方: lvから始まる
    • 可変サイズ: dvから始まる
  • 幅か高さか?
    • 幅: wをつける
    • 高さ: hをつける
    • 小さい方: minをつける
    • 大きい方: maxをつける
    • インライン方向: iをつける
    • ブロック方向: bをつける

各単位をまとめると次のとおりです。

  • 小さなビューポート
    • svw, svh, svi, svb, svmin, svmax, svi, svb
  • 大きなビューポート
    • lvw, lvh, lvi, lvb, lvmin, lvmax, lvi, lvb
  • 可変のビューポート
    • dvw, dvh, dvi, dvb, dvmin, dvmax, dvi, dvb

対応ブラウザ

各単位の対応ブラウザは次のとおりです。

  • Chrome 108で対応(Android・デスクトップ共に)
  • Safari 15.4で対応(iOS・デスクトップ共に)
  • Firefox 101で対応
  • Edge 108で対応

Edge 108については、2022/12/1週にリリースが予定されています リリースされました(2022/12/6)。

▼ Edge 108での動作結果

最後に

iOS Safariの画面の高さいっぱいにヒーローイメージを広げる問題は、長年開発者を悩ませてきたものです。svhdvhはその課題を解決できる単位で、長らく全ブラウザ対応が待たれてきました。今回のChromeの対応により、手軽に使える環境が整ったと言えるでしょう。

今回のウェブサイトの素材は、デザイナーの松下 絵梨さんに作成いただきました。

goal.png

関連資料

GitHubで編集を提案

Discussion