知ってる? iOS Safariでスクロールしただけでリサイズイベントが発生する原因と対処法

  • 104
    いいね
  • 0
    コメント

iOSの標準ブラウザであるMobile Safariにおいて、「ウインドウサイズが変わった」というイベントが発生するのはどんなときだと思いますか? Mobile SafariはiPhone端末のサイズいっぱいに全画面表示されるので、縦持ち・横持ちを切り替えた時「だけ」ウインドウサイズイベントが発生する、というのは間違いです。実は、ウインドウを最初にスクロールした時にもリサイズイベントが発生します。この現象の原因と解決方法を紹介します。

スクロール時にリサイズイベントが発生するデモ

現象を確認するためにデモを準備しました。コンテンツはiPhoneの画面サイズに収まりきれないほど長く、スクロールが必要です。ウインドウリサイズイベントが発生した時に、アラートが出ます。
http://goo.gl/yWHZ3M

JavaScriptには下記の処理が定義されています。

ウインドウリサイズ時にアラートを発生
window.addEventListener("resize", function() {
   alert("ウインドウがリサイズしました。");
})

Mobile Safari (iPhone 6s、iOS 9.1.2)で最初のスクロールをしてみると、縦持ち・横持ちを切り替えていないのにリサイズした旨のアラートが表示されます。

ios_scroll.png

何故こんなことが起こるのか?

iOS 8からスクロール時にアドレスバーが自動で小さくなる仕様となりました。これにより、アドレスバーが小さくなった分だけウインドウサイズが大きくなったと見なされ、リサイズイベントが発生するようになったのです。ウインドウサイズのことを考えれば当然の挙動なのですが、「スクロールしただけでリサイズイベントが発生する」というのはデスクトップでのブラウザに慣れている人であれば違和感を感じるのではないでしょうか。

意図したとおりにリサイズイベントを取り扱うにはどうしたらいいのか?

モバイルコンテンツで、横持ち・縦持ちが変わった時のみリサイズ処理を行うには、下記のような方法があります。

対処法1:画面の横幅が変わった時のみリサイズ処理を行う

iOS、Androidの時は縦持ち・横持ちを切り替えるとは、ウインドウの横幅が変わることと同じ意味なので、横幅が変わった時のみリサイズ処理を実行する方法です。

MobileSafari対応ウインドウリサイズ時にアラートを発生
// ウインドウの横幅を保持
var currentWidth = window.innerWidth;

window.addEventListener("resize", function() {
    if (currentWidth == window.innerWidth) {
        // ウインドウ横幅が変わっていないため処理をキャンセル。
        return;
    }

    // ウインドウ横幅が変わったのでリサイズと見なす。
    // 横幅を更新
    currentWidth = window.innerWidth;
    alert("ウインドウがリサイズしました。");
});

http://jsrun.it/tonkotsuboy/qrVDにデモを用意しました。iOS、Androidの時は縦持ち・横持ちを切り替えた時のみ、デスクトップブラウザではウインドウのりサイズ時にアラートが表示されます。

対処法2:モバイルでは端末の向きが変わった時のみリサイズ処理を行う

iOS、Androidでは端末の向きが変わった時にorientationchangeというイベントが発生します。モバイルではこのイベントが発生した時のみ、リサイズ処理を実行する方法です。

モバイルの時は端末の向きを監視する方法
// ユーザーエージェントの判別
var userAgent = navigator.userAgent;

// スマートフォンの場合はorientationchangeイベントを監視する
if (userAgent.indexOf("iPhone") >= 0 || userAgent.indexOf("iPad") >= 0 || userAgent.indexOf("Android") >= 0)
    window.addEventListener("orientationchange", resizeHandler);
else
    window.addEventListener("resize", resizeHandler);

function resizeHandler() {
    alert("ウインドウがリサイズしました。");
}

http://goo.gl/ariHN0にデモを用意しました。こちらも期待の動作をします。

Mobile Safariでリサイズ処理を扱う時は気をつけましょう

モバイルコンテンツでファーストビュー全体にコンテンツを表示してJavaScriptで処理を行いたい時等にこの現象が問題になります。この挙動を頭に入れておきましょう。