CSSのsvh・dvhが全ブラウザ対応。iOS・Androidの画面いっぱいに要素を広げる最適解
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
の使い方、同様に使えるようになったdvh
やsvmax
などの違い、従来の手法のデメリットをデモを交えて紹介します。
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での動作結果
デモは次から確認できます。
svh
とは
従来使われてきたvh
やvw
とは、ビューポートに対する高さや幅を指します。
デスクトップブラウザのようなビューポートのサイズが固定のものでは十分だったのですが、iOS Safariなどではビューポートのサイズが可変になります。
このうち、ビューポートの高さが最小になった場合の高さを示すのがsvh
というわけです。
ビューポートが大きい場合の高さを取得したい場合は、lvh
を使います。
また、ビューポートの大きさが変わったときの高さを取得したい場合は、dvh
を使います。100dvh
を今回のメインビジュアル表現に使ってしまうと、スクロール時にメインビジュアルの高さが変わってしまうため、向いていません。100dvh
は、全画面に表示するモーダルウインドウやナビゲーションを作る際に役立つでしょう。
その他の単位については後述します。
100vh
・100%
・-webkit-fill-available
では駄目なのか?
なぜ今回作った表現は、100vh
や100%
では駄目なのかと思う人もいるでしょう。従来の表現を100svh
と比べてみましょう。
100vh
だと はみ出る
次のように100vh
を指定したとします。
.hero-image {
height: 100vh;
}
この場合、ヒーローイメージ部分(.hero-image
)はファーストビューからはみ出します。iOS Safariの場合、100vh
は100lvh
と同じ高さになり、大きいビューポートの高さを取ってしまうのです。
ヒーローイメージがはみ出しているので、スクロールしてもヒーローイメージ部分が続いてしまいます。
たまに勘違いされますが、ビューポートの大きさが変わるのは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
)の事情だけのためにhtml
やbody
にheight: 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
の便利さには適いません。
他にもいろいろな単位が使えるようになった
svh
・lvh
・dvh
以外にも、さまざまな単位が使えるようになりました。
vmax
・vmin
について
以前からvmax
・vmin
という単位が使えました。おさらいしておくと、次のとおりです。
-
vmax
: ビューポートのうち、幅か高さの大きい方 -
vmin
: ビューポートのうち、幅か高さの小さい方
sv*
やdv*
と組み合わせられるので、svmax
やlvmin
といった単位が使えるようになります。
vi
・vb
について
「論理的プロパティ(CSS Logical Properties)」に応じたvi
・vb
にも対応しました。
-
vi
:インライン方向 -
vb
:ブロック方向
sv*
やdv*
と組み合わせられるので、svi
やlvb
といった単位が使えるようになります。
ビューポート単位のチートシート
以上をまとめると、次のようにして各ビューポートのサイズを作成できます。
- ビューポートのサイズは?
- 小さい方:
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の画面の高さいっぱいにヒーローイメージを広げる問題は、長年開発者を悩ませてきたものです。svh
・dvh
はその課題を解決できる単位で、長らく全ブラウザ対応が待たれてきました。今回のChromeの対応により、手軽に使える環境が整ったと言えるでしょう。
今回のウェブサイトの素材は、デザイナーの松下 絵梨さんに作成いただきました。
関連資料
Discussion