スマフォでlandscape(横持ち)フルスクリーンサイトを作る際のノウハウ


はじめに

通常のブログや縦長サイトをlandscapeで見る場合は特に特別なことをやる必要はないと思いますが、画面にFIXした「アプリっぽい」サイトを制作するときには色々と癖があり、事前に想定しておく必要のあるものがたくさんありますので、そちらを可能な限りまとめていけたらと思います。
※ いったん、Androidを無視して、Mobile Safari(以下、ブラウザ)に限定した記事になります。
※ ここでいうフルスクリーンとは ブラウザの上下にあるUIバーが隠れて、ディスプレイ全体でウェブサイトを表示している状態を指します。

フルスクリーンにするための手段

iOS9 現在の情報です。

有効なもの

  • オリエンテーションが変わって横持ちになったとき(landscape限定)
  • 長いページを下にスクロールしたとき(landscape, portrait共に)
  • <meta name="apple-mobile-web-app-capable" content="yes"> を設定し、ホーム画面登録させて立ち上げる

無効になったもの

  • iOS6以前の window.scrollTo(0, 1) ハック
  • iOS7のみの minimal-ui viewportプロパティ

実現できないもの

  • jsで任意のタイミングでUIバーを隠すこと(擬似的に orientationchange イベントなどを発火してもフルスクリーンにすることは不可能です。タイミングは完全にユーザーに委ねられています)。
  • <meta name="apple-mobile-web-app-capable" content="yes"> を使わない状態でのportraitフルスクリーン
  • landscape状態でサイトにアクセスした際のフルスクリーン化(必ずportrait -> londscape と orientationchangeイベントを発火させる必要があります)

前準備

現在有効なもののうち、
3つ目の「ホーム画面に登録させる」はユーザー頼みになってしまい現実的ではなく、
2つ目も、今回は画面FIXしたアプリ風のサイトを目指すので目的に即していません。
というわけで1つ目の オリエンテーションが変わって横持ちになったとき にフォーカスすることにします。

ただ、単純にlandscapeにしたらフルスクリーンになる(上下のUIバーが隠れる)わけではありません。
ポイントとしては表示コンテンツ(bodyの高さ)がディスプレイサイズ以上になっている必要があります。
なので


<body>
    ...
</body>


body {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 101%; // ここがポイント
}

このようにします。
これでlandscapeにすると確実にフルスクリーンになります。

フルスクリーンを解除させないTips

上記で無事landscapeのフルスクリーンは実現できたので、あとはひたすらウェブサイトを構築していくのみですが、
あくまでこのフルスクリーンは「擬似」的なものなので、「フルスクリーンが解除してしまう(UIバーが出てきてしまう)弱点」がかなりあります。
ここからは、「なるべく」そうならないようなTipsをご紹介していきます。

1.スクロールはjsで制御すべし

上にスクロールした瞬間にUIバーが再表示されてしまいますので

document.body.addEventListener('touchmove', function (e) {
    e.preventDefault();
});

こんな感じで bodyのtouchmoveを無効にしましょう

そしてスクロールで表示したいコンテンツはjsの擬似スクロールで実装しましょう。
※ 要素内スクロール(overflow:scrollとか)でも一見いい感じなのですが、要素を一番上までスクロールしたあとも上方向にスクロールを続けようとするとUIバーが出てきてしまいます。

ちなみに僕は普段 https://github.com/mjohnston/scroller をベースに魔改造した独自ライブラリを使っております。

2.クリックイベント系に注意すべし

クリックイベント系でURLを更新する(ページが切り替わる)とUIバーが出てきてしまいます。
対策は以下のようにします(hashchangeを用いたSPAサイトを想定)。

<a href="#!/hoge/hoge" id="hoge">HOGEのページ</a>
var el = document.getElementById('hoge');
el.addEventListener('click', function (e) {
    e.preventDefault();
}, false);
el.addEventListener('touchstart', function (e) {
    location.hash = '#' + this.href.split('#')[1];
}, false);

このように touchstart リスナー内で hash を更新します。
ちなみにjsで更新すればいいというわけでなく、clicktouchend のリスナー内で hash を更新するとUIバーが出てきてしまいます。
また touchend のリスナー内で setTimeout を用いて非同期でも更新してみましたが、ダメでした。

3.ボタンなどの配置場所に注意すべし

フルスクリーンになったあと、画面の上部や下部をタップするとUIバーが出てきてしまいます。
具体的にはiPhone5sまで(landscape時の高さが320pxの端末)では上は約20px、下は約40px
iPhone6以降は上の約20pxのみ(下はタップしてもUIバーは出てきません)がUIバー表示領域になります。
なので、iPhone5以前も考慮するとなると縦320px中、60px分がタップ禁止区域になるので
縦260px以内にボタンなどが収まるようデザインをしなくてはいけません。

また、個人的には60pxというのはホントにギリギリのラインなので、
できたらもう10pxぐらいは余裕を持って、縦240px以内に収まるようにできればベストかと思います。