CSSの新しい単位「lvh」「svh」これでiOSのSafariで100vhがビューポートの高さではない仕様に対応できる
Post on:2022年5月26日
Safari 15.4(最新は15.5)で新しいビューポート単位「lvh
」「svh
」がサポートされました。ビューポートを基準にした単位で、この単位を使用することで、iOSのSafariで100vhがビューポートの高さではないという仕様に対応できます。
今まではCSSの-webkit-fill-available
がその対応方法でしたが、ネストされた要素やcalc()
内では使用できません。新しいビューポート単位を使用すると、そういった問題もなくなります。
The Large, Small, and Dynamic Viewports
by Bramus
2021年の記事ですが、Safari 15.4でこれらの新しいビューポート単位がサポートされたので、このタイミングで紹介します。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
W3CのCSS Values and Units Module Level 4で、ビューポート単位についていくつか仕様が変更されました。Large、Small、Dynamicといったビューポートサイズの単位が追加されました。
この新しく追加された単位のおかげで「iOSのSafariで100vh」における問題を解決できるようになります。
左: アドレスバーを非表示、右: 表示されてるとその分下に
詳しくは、下記をご覧ください。
- iOSの100vhでアドレスバーがあっても高さいっぱいに表示するCSSのテクニック
- height: 100vh;を定義したのに、iOSのスマホで高さいっぱいに表示されないのを解決するCSSのテクニック
新しく追加されたビューポート単位とは
CSSWGでは既存のvw
, vh
, vmin
, vmax
に加えて、さらに追加のビューポート単位が定義されました。
参考: The Large, Small, and Dynamic Viewport Sizes -W3C
追加されたビューポート単位は、下記の通りです。
- Large Viewport (
lvw
,lvh
,lvmin
,lvmax
) - Small Viewport (
svw
,svh
,svmin
,svmax
) - Dynamic Viewport (
dvw
,dvh
,dvmin
,dvmax
)
Large Viewport
Large Viewportは、動的に拡大・縮小されるあらゆるUAインターフェース(アドレスバーなど)が格納されると想定したビューポートサイズを基準に定義されています。これにより、コンテンツが展開されたときにそのインターフェースの背後に隠れる可能性があることに注意しながら、ビューポートを満たすことが保証されるコンテンツのサイズを作成できます。
単位は接頭辞に「l」をつけ、lvw
, lvh
, lvmin
, lvmax
となります。
たとえば、100lvh
はラージビューポートの高さの100%を表します。
100lvh
はラージビューポートの高さの100%
Small Viewport
Small Viewportは、動的に拡大・縮小されるあらゆるUAインタフェース(アドレスバーなど)を拡大すると想定したビューポートサイズを基準に定義されています。これにより、コンテンツがビューポートに収まるようなサイズを設定できます。
単位は接頭辞に「s」をつけ、svw
, svh
, svmin
, svmax
となります。
たとえば、100svh
はスモールビューポートの高さの100%を表します。
100svh
はスモールビューポートの高さの100%
Dynamic Viewport
Dynamic Viewportは、動的に拡大・縮小されるあらゆるUAインターフェース(アドレスバーなど)を動的に考慮してサイズ設定されるビューポートです。これにより、UAインターフェイス要素が表示されているかどうかにかかわらず、コンテンツがビューポートに正確に収まるようにサイズは自動的に調整されます。値は100lvh
(最大)および100svh
(最小)の範囲内になります。
単位は接頭辞に「d」をつけ、dvw
, dvh
, dvmin
, dvmax
となります。
このDynamic Viewport Unitは、UAインターフェイスの変化に合わせて自動的に伸縮するUIが欲しいところです。100dvh
を定義すると、自動的に適応されます。
1 2 3 |
body { height: 100dvh; } |
既存のテクニックではダメですか?
新しく追加されたビューポート単位を使用する代わりに、既存のJavaScriptでの回避方法や下記に示すCSSの回避方法を使用することができないのかと思うかも知れません。
1 2 3 4 5 6 7 8 9 |
body { height: 100vh; } @supports (-webkit-touch-callout: none) { body { height: -webkit-fill-available; /* ❌ これはしないでください! */ } } |
上記の回避方法は期待するものを実現しますが、body
の高さを「ビューポートの高さいっぱいにするだけ」です。これは-webkit-fill-available
がアイテムを囲む要素(ここではビューポート)内に引き伸ばすからです。-webkit-fill-available
を使用した方法ではビューポートではなく親要素が参照されるため、ネストされた要素では機能しません。
100dvh
を使用すれば、期待するものを簡単に実現できます!
さらに、calc()
内で-webkit-fill-available
を使用できないため、「囲んでいる要素の半分のサイズ」といったこともできません。height: calc(-webkit-fill-available * 0.5);
は無効なCSSです。この記述がいつか使用できるようになったとしても、ビューポートに対してネストされた要素のサイズを定義したい場合は、再び問題が発生します。
だから、新しいビューポート単位が必要なのです 🤩
なぜSafariだけ仕様が違うのか
新しいビューポート単位(l*/s*/d*)は、すでに存在するvw
, vh
, vmin
, vmax
単位に追加されるものです。これらの古い単位には明確な定義がなく、どのように振る舞うかはUA(ブラウザ)次第となります。あるブラウザ(現在のSafari)はvh
をlvh
のように振る舞い、他のブラウザはvh
をdvh
のように振る舞います。
また、Dynamic Viewportの振る舞いはUAの選択次第です。あるブラウザはインターフェイスが変化している間、すぐにその値を更新するかもしれませんし、他のブラウザはUIが遷移した後でのみ値を更新するかもしれません。仕様では、、、どちらでも問題ありません。
UAは関連するインターフェースを拡張および収縮させるときに、動的ビューポートのパーセンテージ単位をアニメーション化する必要はなく、代わりにUIアニメーション中に関連するインターフェースが完全に拡張または収縮されたかのように単位を計算することができます。
スクリーン上のキーボードのようなものは考慮されていません。そのために、近日公開予定のVirtual Keyboard APIがあります。
論理プロパティの単位
仕様では論理プロパティの単位も定義されており、large/dynamic/small viewportのインラインサイズとブロックサイズである vi
, dvi
, svi
と vb
, dvb
, svb
についても説明されています。
小さなことですが、とても嬉しい追加です。
ブラウザのサポート状況
2022年5月現在、ブラウザのサポート状況は下記の通りです。
【訳者注】これらの単位を使用したいSafariにサポートされています。他のブラウザではvh
をdvh
のように振る舞うので、フォールバックにvh
を記述すれば問題ありません。
下記のデモページでdvh
をサポートしているかどうか試すこともできます。
デモページ: Safari 15.4で表示
デモページ: Chrome 101で表示
終わりに
Safariで100vh
がビューポートの高さではないというバグが最初に報告されたのは、2015年にさかのぼります(WebKit Bugzilla)。CSSWGで関連するIssueは2019年にさかのぼるため、この問題を解決するために動きがでたのは素晴らしいことです。
ビューポート単位の追加に関する最終的な合意がされたので、Safari 15.4で実装されました。
sponsors