スマートフォン用サイトを制作するデザイナーさんに伝えたいWebブラウザのViewport(表示領域)の話。エンジニアにも役立つかも。 Part2
Part1の続きです。Part1はこちら↓
今回は
・少し厄介なランドスケープ時のViewportの高さの話
・かゆいところに手が届きそうで届かないCSSのvw/vhの話
・これまた厄介なアプリ内ブラウザ (WebView)でのvhの話
の三本立てでお送りしたいと思います。
・・・
少し厄介なランドスケープ時のViewportの高さの話
Webコンテンツ閲覧中に、スマートフォンを横向きで使うシチュエーションって個人的にはそんなにないですが、全画面 (html, bodyのwidth, heightが100%)のコンテンツだったり、キービジュアルをViewportに合わせた大きさにする、といったようなコンテンツではランドスケープ時の挙動に注意が必要です。
Android Chromeの場合
Android Chromeの場合はランドスケープ時の挙動はポートレートのときと変わりません。スクロールできるコンテンツの場合はアドレスバーが縮みます。全画面コンテンツの場合はスクロールできないのでアドレスバーがそのままです。また、OSのステータスバー(画面の一番上のバー)も消えません。なのでViewportはかなり横長になります。
iOSの場合
iOSの場合は、ポートレート時とはいくつか違いがあります。
まずOSのステータスバーが消えます。
また、フッタ (下部のUIバー)の挙動が端末によって異なります。iPhone6サイズ以上の場合は、ヘッダにUIが集約され、フッタが非表示になりますが、iPhone5サイズの場合はポートレート時と同じく、フッタが表示されます。なので、初期表示時はコンテンツがあまり見えない状態です。
そして、次の点がiOSのポートレート時において、個人的に一番厄介だと思っているポイントです。
それは、「高さが100%のコンテンツでも、スクロールが発生する」という点です。
Part1でも述べた通り、今回制作した「Viewport Checker」は、スクロール後の挙動を確認できるようにするため、スクロールできる仕様になっていますが、このアプリ内で定義しているViewport sizeは、全画面コンテンツと同じなので、見た目的には全画面コンテンツと同じ状態になります。
それを踏まえてもう一度Viewport Checkerの結果を見てみると。。。
↑のように、高さが100%のはずなのに、コンテンツが見切れています。
この挙動は、画面の小さいスマートフォンで表示領域を少しでも確保するためですね。
つまり、ランドスケープの場合は全画面コンテンツでもユーザにスクロールをしてもらわないといけません。
(ちなみに厄介と言っているのは製作時においての話で、横向きでもユーザ体験を損なわないようにしているこの挙動は理にかなっていると思います。)
というわけで、全画面コンテンツをランドスケープで作る場合は
iOSの場合はユーザにスクロールしてもらわないと、
コンテンツが見切れる
Androidの場合はヘッダが非表示にならないので、
表示領域が横長になりがち
ということになります。エンジニア泣かせですね。。
ただし、iOSの場合、デバイスを回転させてポートレートの状態からランドスケープにした際に、自動的にヘッダ(またはフッタ)が消えて全画面になります。これは多くのユーザがWebブラウザを使用する際、基本的にはポートレートで使用している前提でこのような仕様になっているのかと思います。
なので、iOSはまぁいいとして、Androidでランドスケープの全画面コンテンツを作る場合、ヘッダが消えないので表示領域が横長になりがち問題がありますが、これを許容するか、コンテンツの高さにheight: 100vhを設定して、スクロールを促すアテンションなどを入れるかのどちらかになりそうです。
・・・
かゆいところに手が届きそうで届かないCSSのvw/vhの話
フロントエンドエンジニアの方にとってはもはや常識ですが、vw/vhはCSSで使える非常に便利な単位で、表示領域のに対して相対的に値を決めることができます。100vwは画面幅いっぱいと同じ長さになり、50vwは画面の半分の長さ、ということになります。
この単位を初めて使えると知ったときは「全画面コンテンツとか、キービジュアルの高さを100%にするのに使えるのでは?」と思ったんですが、これはこれで一癖ありました。vhに。
上の画像を見るとわかるように、vhはスクロール後のViewportの高さになります。これはスクロール前も値が変わらないです。
vhがスクロール前のViewportの高さだったら、キービジュアルを画面いっぱいにする、あのよくあるやつが、JSを使わずにCSSだけで実現できるんですが、そううまくはいかないようです。。
なので、キービジュアルを全画面にする場合は、PCサイトの場合はwindowのresizeイベント、スマホサイトの場合はwindowのorientationchangeイベントでキービジュアルの高さをwindow.innerHeightにしています。
(スマホはなぜorientationchangeなのかというと、これも割と既知の問題ですが、ヘッダやフッタが縮んだり非表示にある関係で、スクロール時にresizeイベントが発火するので、スクロールしながらキービジュアルが「ガガガッ」っとリサイズするのを防ぐためです。
・・・
これまた厄介なアプリ内ブラウザ (WebView)でのvhの話
さて、ここで忘れてはいけないのがアプリ内ブラウザ (WebView)での見え方。
SNSでシェアされたサイトをアプリで閲覧する場合、iOSのアプリ (TwitterやFacebookやLine)で閲覧しているとほとんどのユーザがWebViewでサイトを閲覧することになると思います。
Androidの場合は、アプリからリンクをタップした場合、WebViewだったり、ブラウザを選択するポップアップが出てきたりとアプリによって挙動が異なりますが、デフォルトの設定でWebViewで表示されるものもあるため、無視できません。
WebViewはSafariやChromeとはことなる動きをしたりして、今までさんざん苦しめられてきたので、今回制作したViewport CheckerをWebViewで閲覧してみたところ、案の定アプリによって挙動が異なりました。。勘弁してくれ。。
iOS Facebookアプリ (ver. 190.0)
スクロール前とスクロール後でvhの値が違う。。Safariとは違う挙動です。ランドスケープ時も同じでした。
しかも、ランドスケープに至っては、100%のはずなのに、ちょっとはみ出している???
iOS Twitterアプリ (ver. 7.32.1)
ポートレート、ランドスケープともに、Safari同様vhの値はスクロール後も不変でした。
ただし、ポートレートの場合のみ、vhの値がどこを参照しているのかよくわからない値になりました。Viewport Sizeとも違うし。。何だこの値は。。
ランドスケープのViewport sizeのheightの値はとwindow.innerHeightと同じ値に。これもSafariと違いますね。コンテンツがはみ出していません。
iOS LINEアプリ (ver. 8.13.0)
LINEアプリもスクロール前と後でvhの値が変わってしまいましたが、iOSのFacebook、TwitterのWebViewに比べれば割とまともな挙動かもしれません。。
ちなみにどのアプリも、ポートレートからランドスケープにした場合、Safariのようにヘッダを縮めてくれませんでした。
ちなみに、AndroidのWebViewはChromeと挙動がほぼ同じでした。とくにWebViewのことは意識しなくて大丈夫そうです。
画面サイズやアプリにによってはヘッダが非表示ならないなどの差はありそうですが、iOSに比べるとおかしな挙動はなさそうです。
・・・
とまぁこんな感じで、スマホブラウザでのViewportの扱いは、ご覧の通りOSやアプリ間でこれだけ差異がある (しかもめちゃくちゃややこしい。。)ので、制作するコンテンツによって最終的にどのような体験、見え方が一番ベストなのかをしっかり考える必要があるかと思います。
長くなってしまいましたが、ここまで読んでいただいてありがとうございました。
サポートいただければ、レッドブルを飲んでより頑張れると思います。翼を授けてください。