CSSで高さいっぱいの100vh指定。スマホでアドレスバー分はみ出さないための対策


トップページのメインビジュアルをファーストビューの画面いっぱいに表示させたいという依頼があります。
画面いっぱいをメインビジュアルで覆うことで、表紙のような表現をするデザインですね。
アーキプラス 浜松市の注文住宅と開業支援
こういったデザインをしたいときに、画面の幅いっぱいにサイズを指定するのは簡単ですが、
画面の高さいっぱいにサイズを設定するのが実は意外と面倒なんです。

画面の高さを基準とする単位vh

画面に対してサイズを指定するときに使うと便利な単位は何でしょうか。
vwやvhという単位を知っていますか?
viewport widthやviewport heightという意味で、ブラウザの表示領域のサイズを100としたときのサイズの指定方法です。
100vwや100vhがそれぞれ画面の幅と高さになり、
とすると、

width:100vw;
height:100vh;

とすれば、画面いっぱいの要素が作成できます。
あれ?簡単でしたね。
このように、実はちょうど画面いっぱいのサイズの要素を作るのは難しくはありません。

スマートフォンでアドレスバー分押し出される問題

PCではこのように簡単なのですが、スマートフォンについては問題があり、
このように、アドレスバーが無い状態のサイズを100vhとして定義されるので、
アドレスバーが表示された状態では、その分だけ下に押し出されてしまいます。
Web 1920 – 1
これはvhの単位に問題があるというよりは、スマホの場合は限られた画面の中でできるだけ表示領域を大きくするために、
アドレスバーやツールバーなど、ブラウザ独自に可変要素が存在するから固定値では状態によっての対応ができないんですね。
iPhoneでは、上にスクロールするときと下にスクロールするときでアドレスバーの高さも変わります。
Web 1920 – 2
個人的にはアドレスバー分押し出されるくらいいいじゃないかと思ったりするんですがw、
案件によってはそのあたりも厳密に対応しないといけないこともあり、いろいろと調べてみました。

スマートフォンで画面の高さを指定する方法

  • PCはvhで問題なし
  • スマホはvhだと状況によってはみ出る
  • アドレスバーを含めないCSSでのサイズ指定
  • デバイスに依存しない高さの指定

これらを考えていきましょう。

いろんな状態が想定できますが、とりあえずはページを開いた直後の状態でうまく表示されているということを目標にしましょう。
つまり、アドレスバーの分のサイズが含まれないサイズの取得ができればいいですね。
※たいていは、ページを開いたときにこうなって欲しいという要望なので、その状態で問題なければ仕様条件満たすことも多いです

iPhoneでのSafari対応

こちらは一時期解決策として話題になった内容で、
結果的には全てを解決してくれるものではなかったので、一応紹介しておきますがさっと流す程度で大丈夫です。

iPhoneの対策として、Safariでアドレスバーを含まないサイズを利用するのに、
次のような値が用意されています

-webkit-fill-available

このように指定します

body{
  height: 100vh;
  height: -webkit-fill-available;
}

一時期、これが解決方法だと騒がれていましたが、
Chromeのバージョンアップにより、Chromeで動作がおかしくなるということがあり、
じゃあ、Chromeでは適用されないようにするために

/* Avoid Chrome to see Safari hack */
@supports (-webkit-touch-callout: none) {
  body {
    /* The hack for Safari */
    height: -webkit-fill-available;
  }
}

このようなハックが紹介されたりしていました。
でも、これではAndroidのChromeに対応できないということもあり、
今のところCSSだけでは全てのデバイスとブラウザに対して解決はできなさそうです。

JavaScriptを使って高さを指定

特殊なプロパティ値を調べたり、ブラウザハックをしたりと様々な条件分岐をCSSだけでするのはやはり無理があります。
ということで、こういう場合はjavascriptを使うのが一番安定しているのではと思います。

javascriptもしくはjQueryでは、アドレスバーを除いた高さを以下のようにして取得できます

window.innerHeight  //javascript

$(window).height()  //jQuery

なので、これをそのままスタイルとして指定します。
jQueryでの方法を書いておきます。

var height = $(window).height()  // 画面の高さをpxで取得
$('#target').css('height',height); // id="target"の要素に高さを設定

いやー、簡単ですね。w
一応、これで開いたときに画面全体を覆うメインビジュアルは完成です

最初っからこうすればいいのにって思いますが、
JSが扱えないコーダーも少なくはないし、CSSで何とかしたいという気持ちはとてもよくわかるので、
できることならレイアウトはCSSでよいと思いますが、今回はこれが良いかなと思います。

ただ、これでも問題はあって、
スマホを縦横持ちかえたときに、CSSのように動的に対応できません
こういった場合に対応するには、resizeなどのイベントを受け取ってその中でサイズを再設定するようなプログラムも必要です。
 
また、さらに発展的な方法ですが、
今回の問題はvhの高さの定義が、理想と違っている点にあるので、
vhの高さを自分で定義しなおすことができれば、その他の場所でvhを理想の動作で利用できます。
CSSのカスタムプロパティを使ってvhの単位自体をJSで定義するということでこれが実現できるので、
これについては、いずれまた紹介したいと思います。

ブラウザサイズに合わせたメインビジュアルといっても、突き詰めるとこれだけ問題や解決策が出てきます。
クライアントからは軽い感じで不具合を指摘されて・・・それを何時間もかけてあれこれ調べるってのはコーダーのあるあるだと思いますw

案件ごとに求められることは違うと思いますが、
どこまでやるのか、どこで妥協するのかを決めるのも大切です。
いくつかの選択肢は持っておきましょう。

[RelService] [Service]