CSSで要素をスマホの画面いっぱい、つまり全画面に表示しようとした時に100vhを使うとアドレスバーの高さ分要素がはみ出しますが、この対処法です。
iOS,Android共にスマホのブラウザは縦スクロール時にアドレスバーやメニューが出たり、引っ込んだりしますが、この動作のせいで画面ピッタリに要素を表示することが難しくなっています。
他にも画面回転などの動作もあり、結構ややこしいのでサンプルコードと画像も使いながら、要素をスマホの画面いっぱいに表示する方法を解説します。
CSSだけでも対処できますが、画面回転も考えるならJavaScriptも必要です。
この記事の目次
CSSの100vhでスマホの画面いっぱいに要素を表示する
はじめに...デバイスのビューポートを取得するためにCSSでは「100vh」が使われると思いますが、この100vhで要素を画面ピッタリに表示する方法が当記事の内容です。
この記事ではCSSやJavaScriptを使って要素をスマホの画面いっぱいに表示する方法として以下の3つの方法をご紹介します。
- CSSの「height:100%」を使う方法。
- CSSの「-webkit-fill-available」を使う方法。(これはおまけ)
- JavaScriptでスマホの画面の高さを算出し、CSSでそれを使う方法。
現状、実用的なのは③のJavaScriptで画面の高さを計算したあと、これをCSSで使用して画面いっぱいに要素を表示するという方法です。ただ結構難しいかもです。
もう少し時代が進めばCSSのみで全デバイスに対応できそうなところまでは来ているのですが、今はまだJavaScriptも使わないと色々な端末(OS、ブラウザ)に対応することが出来ない感じです。このへんも記事中で触れます。
留意点
CSSの挙動はOSやブラウザのバージョン、サイト環境によって異なるという点はご了承を。ブラウザも新しいCSSに対応できるように日々進化していますので。
では100vhでスマホの全画面に要素を表示する方法を見ていきましょう・w・
100vhで要素を画面いっぱいに表示する方法
まず“100vhを使うとスマホで要素がはみ出す”という問題をおさらいします。
お読みいただいている方のレベルが分からないのでやはりここから書きます。
アドレスバーが原因のこの問題を既にご存じの人は、適宜読み飛ばして下さい!
CSSで要素を画面いっぱいに表示したい時は「100vh」が良く使われます。
vhは「viewport height」で、100vhとすると画面の高さ100%分の高さで要素を表示できます。(画面いっぱいに表示したい時、通常横幅である100vwは不要です。)
使い方は以下のように任意の要素にこのプロパティを指定するだけでOKです。
#content{ height:100vh; }
今回、例としてこのIDがcontentの要素を使います。
#content{ height:100vh; background: linear-gradient(to bottom left, gray 50%, blue 50%); }
こんな感じに背景にグラデーションを追加して分かりやすくしました。
これをブラウザで表示すると以下のような感じになります。
- (例)パソコン版Chromeで表示した画面
- (例)Chromeの開発者ツールでスマホ画面を検証した画面
Chromeで確認してみると、パソコンの表示でもスマホの表示でも要素が見切れることなく画面の高さピッタリに表示されているのが分かります。
スマホ実機では100vhで要素がはみ出す
続いて、手元にある実機(iPhone12 mini)で確認してみます。
少し分かりにくいですが、パソコンで見た時と比べるとスマホ実機では要素の下部分がはみ出し、見切れてしまっているのが分かるかと思います。
グラデーションの下部分が画面の端にピッタリ来ていませんね...。
スクロールして見るともっとよく分かりますので、様子をGIFにしてみました。
こんな感じです。
100vhで画面の高さいっぱいという指定のはずが、画面ピッタリになっていません。
画面を横向きにしてみるとこんな感じです。
横向きでも同じく画面からはみ出した要素が見切れてしまいます。
原因はスマホのブラウザのアドレスバー
既にお察し方もおられると思いますが、CSSの100vhがスマホで画面ピッタリにならないのはスマホのブラウザのアドレスバーとメニューバーが原因です。
単にheight:100vh;と指定しただけでは、Webサイトにアクセスした時点のその端末の画面の高さが適用されます。
つまり、
- アドレスバー(メニュー)が出ている状態。
- アドレスバー(メニュー)が引っ込んでいる状態。
この2つの状態で端末の画面の高さが異なるのが原因です。
height:100vh;ではどちらか一方の高さしか保持できないのですね~...。
そして、このアドレスバー(メニュー)は縦スクロールの度に出たり、引っ込んだりする仕様なので、高さを100vhとした要素が見切れてしまう問題が発生します。
ではスマホの画面いっぱいに要素をピッタリ表示したい時はどうするか?です。
CSSの100vhで要素がはみ出す時の対処方法
前置きがかなり長くなってしまいまいましたが、ここから100vhで要素がはみ出して見切れてしまう時の対処方法のご紹介です。
現状全デバイスに柔軟に対応するにはCSSだけでは困難ですが、CSSだけで問題なく動く環境 or 少し妥協しても良いならCSSのみで対応することも可能です。
CSSだけならJavaScriptを使わないのでページを比較的軽量に仕上げることはできますが、スマホの画面回転に対応しつつ全デバイスにも対応したいなら、JavaScriptを使って端末ごとの正確な画面サイズを算出するしかありません。
以下の解説中にある問題をパスできるならCSSだけで対処するのもアリです。
いずれにしても自分のサイトに合う方法で解決していただければと思います。
CSSのみで対処する方法
まずはCSSのみで対処する方法です。
100vhは端末の画面サイズ(ビューポート)の高さいっぱいという指定ですが、100%という指定をしても画面の高さいっぱいという指定になります。
height:100%という書き方は昔からあるのでどんな端末、ブラウザでも動きます。
ということで「height:100vh;」を「height:100%;」に変えれば良いです。
#content{ height:100%; background: linear-gradient(to bottom left, gray 50%, blue 50%); }
これならJavaScriptで画面サイズを計算することなく画面いっぱいに表示できます。
CSSのみで対処するならこれが一番簡単な方法です。
が、100%というのは親要素のサイズを元に100%という計算です。
つまりHTMLの下層にある要素を画面いっぱいに表示したいとなると、その上にある親要素全てに「100%」の指定をして要素のサイズを引き継いでやらないとダメです。
これが結構面倒なうえ、場合によってはスマホの画面回転に対応できません。
iPhoneに対応するだけなら「-webkit-fill-available」も検討
iPhoneだけ対応させるならCSSの「-webkit-fill-available」というプロパティが有効です。使い方は簡単でheight:100vh;と共に以下のように記述すればOKです。
#content{ height:100vh; background: linear-gradient(to bottom left, gray 50%, blue 50%); height: -webkit-fill-available; }
これでiPhone(iOS-Safari)だけ100vhが画面ピッタリになります。
ただし、Chromeで見た目がおかしくなることがあるので「@supports (-webkit-touch-callout: none)
」で対Chromeへのフォールバックが必ず必要です。
@supports (-webkit-touch-callout: none){ html{ height: -webkit-fill-available; }
そしてAndroidには対応できません。画面回転も多分無理です。はい。
この方法はiPhoneしかアクセスできないサイトでない限り使い物になりません。
将来的にはCSSだけで完全対応可能になるか?
ここまで触れてきたスマホのアドレスバー(メニュー)が原因で、100vhを使っても要素を全画面表示することが出来ないという問題ですが、今後はCSSだけで対応できるようになりそうです。
CSSには「100svh」や「100dvh」という新しいプロパティが用意されており、これを使えばアドレスバー問題は解決できるとのことです。
但しiOS15.4以上?で対応、パソコンのブラウザはまだ未対応のものがあるといった問題があるため、今現在は実用できるレベルではないようです。
CSSとJavaScriptを使って対処する方法
先述の通りCSSだけでは100vhを使った時に、全端末の画面ピッタリに表示させることは困難です。また、スマホの画面回転には対応できないのが普通です。
(新しいブラウザなら回転時も動くかも…。旧verに対応不可なので結局✕ですが。)
そこで全デバイス、画面回転に柔軟に対応するためにJavaScriptを使います。
OS、ブラウザ、バージョン、パソコンかスマホかiPadという端末の種類、縦横の画面モードに関係なく正確なビューポートが算出できるこの方法が一番オススメです。
具体的な処理の流れは以下のような感じになります。
- アクセス時にJavaScriptで1vhを計算する。
- CSSのcalcを使って100vhに計算し直して使う。
- 画面回転時(リサイズ)時にはJavaScriptで再計算をかける。
- JavaScriptで再計算したvhをCSSで使う。
デバイスに関係なく対応するには安全で確実な方法です。
初回アクセス時とresizeイベントが発火するごとにCSSで使うvhを自前で算出、用意する感じですね。
JavaScriptでvhを自前で用意してCSSで使う
ではやり方を見ていきます。
既に長くなっているので、コードの説明は割愛気味でいきます!
JavaScriptのメソッドについて気になる方は各自お調べ下さい...。
JavaScriptの記述例
//デバイスの画面の高さ(1vh)を算出する関数 function setHeight() { let vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`); } //アクセス時に関数を実行 setHeight(); //画面回転(リサイズ時)に関数を実行する window.addEventListener('resize',setHeight);
全てがポイントですが、こう書けば1vhを算出して変数に格納でき、格納した値はCSSの方に渡して使うことができます。これは結構有名な方法です。
また関数をresizeイベントが発火した時に実行されるようにしています。
CSSの記述例
#content{ height:100vh; height: calc(var(--vh, 1vh) * 100); }
100vhはcalcに対応していないブラウザへのフォールバックです。無くても動きます。
calc(var(--vh, 1vh) * 100);
のところでJavaScriptで算出した1vhを100倍して100vhとして使っています。
resizeイベントでvhを算出する時の問題点
コード自体は先ほど紹介したJavaScriptおよびCSSをサイトで読み込めば動きます。
が、今回使用したresizeイベントには注意点と問題点があります。
1つめがスマホでは画面回転だけでなく、縦スクロール時にもresizeイベントが発火してしまうという点です。これもアドレスバーが原因です。
対処方法は別の記事(↓)に詳しく書いていますので、こちらをご参照下さい。
関連記事
スマホの画面回転時にイベントを発火して何か処理する方法。
→resizeで画面回転時に発火させるの項目へジャンプ
2つ目の問題点がresizeイベントは処理時に若干遅延させてやらないと、正確な画面サイズが取れずにCSSに反映されない時があるという点です。
これはJavaScriptの仕様が原因です。
コチラも対処方法を別の記事(↓)に詳しく書いています。
resizeイベントの代替案orientationchange
分からねぇー!!という方は先ほどのコードの最終行、
window.addEventListener('resize',setHeight);
の部分を
window.addEventListener('orientationchange',setHeight);
という風に変更すればresizeイベントの大きな問題点2つをパスしつつ、画面回転にも対応できるはずです。
ただ全デバイス対応を考えるとresizeイベントの方が安全に動きそうではあります。
orientationchangeを使う時はうまく動かない端末が出てきてもおかしくないと思っておいて良いかもしれません。
まぁーJavaScriptを使う方法も突き詰めればかなり面倒です!
全デバイス、縦横対応で画面ピッタリに要素を表示するのは本当に骨が折れます。
まとめ
以上、CSSの100vhを使ってスマホの画面いっぱいに要素を表示する方法。
そしてスマホの実機で100vhがはみ出して見切れてしまった時の対処方法でした。
想像以上に長くなってしまったのでこの記事の内容をもう一度まとめます。
この記事の要点は以下です。
まとめ
- CSSで全画面表示したい時には100vhを使う方法が定番。
- CSSの100vhはスマホのアドレスバーが原因ではみ出し、見切れる。
- 100vhでスマホの画面ぴったりに表示するにはCSS変更かJavaScriptを使用。
- 一部条件をクリア、妥協すればCSSのみでこの問題に対処可能。
- 全デバイス、スマホの画面回転にも対応するならJavaScriptが安心安全。
- 将来的には新しいCSSのプロパティのみで対処可能になるはず。
JavaScriptで実現するのはコードは簡単ですが、それなりに詳しくないと意図しないところでvhが計算されたり、変にページが重たくなったりするので注意が必要です。
長い記事を最後までお読みいただきありがとうございました。
100vhをスマホの画面いっぱいに常に表示するのって、結構難しいですね色々...。
ではではこのへんで・w・