iPhoneでモーダルの背景のスクロールを止める

iPhoneでモーダルの背景のスクロールを止める


以前の記事「モーダルの背景のスクロールを止める

上の記事で、メニューなどをモーダルで出す場合に背景のスクロールを止める方法を書いたのですが、やはり、iPhone 実機ではうまくいきません。再度挑戦です。



iPhone(iOS?)以外の場合

iPhone 以外は上の記事で問題ないと思います。モーダルを開いた時に bodyopen などのクラスを追加します。たとえば、


document.getElementById('トリガー要素のid').addEventListener('click', function(){
  document.body.classList.toggle('open')
});

として、CSS で

body.open {
  overflow: hidden;
}

とすれば止まります。


今回の件でいろいろググってみたところ、height: 100%;html { overflow: hidden;} が必要との記事が多かったのですが、私の環境では必要ありませんでした。いろいろ試してみるのが一番ですね。


iPhone の場合

iPhone しか持っていませんので、iOS 共通のことがどうかわかりません。おそらくそうだとは思いますが、iPhone 上の Safari と Chrome でのチェックのみです。


モーダルの背景のスクロールを止める(iPhoneの場合)

上の以前の記事の方法では問題が発生します。モーダルを表示しない通常のコンテンツでのスクロールがうまくいきません。一応スクロールはするのですが、いわゆるヌルヌル感がなくなります。


で、いろいろググりましたら、 preventDefault() を使うという記事があり、なるほどということでやってみたのですが、当然ながら、これを使いますとモーダルのスクロールまで止まってしまいます。

こういう方法を考えてみました。

結局、背景がスクロールしてしまうのは、モーダルがもうこれ以上スクロールできない状態の時に背景がスクロールするわけですから、モーダルが一番上や一番下までスクロールしたら、もうそれ以上スクロールしないようにすればいいわけです。ですので、モーダルが一番下までスクロールされたら、preventDefault() でイベントをキャンセルし、そのままではキャンセルされたままになってしまいますので 1px だけスクロールさせキャンセルを解除します。一番上までスクロールしたときも同様にします。


モーダル表示のトリガーが関数 togglemodal() を呼ぶとして、

function togglemodal() {
    if(!document.body.classList.contains('open')){
        document.body.classList.add('open');

        var elem = document.getElementById('モーダルのid');
        elem.addEventListener('touchmove', function(e) {
            var scroll = elem.scrollTop;
            var range = elem.scrollHeight - elem.offsetHeight - 1;
            if (scroll < 1) {
                e.preventDefault();
                elem.scrollTop = 1;
            } else if(scroll > range) {
                e.preventDefault();
                elem.scrollTop = range;
            }
        });

    } else {
        document.body.classList.remove('open');
    }
}

これで、iPhone 実機でもうまくいっています。