モーダルを開いている時にページがスクロールしてしまうのを防ぐCSSとJavaScriptのテクニック

ページ上でモーダルを開き、スクロールして、モーダルを閉じると、通常そのページはモーダルを開いた時とは別の場所にスクロールされた状態で表示されてしまいます。そして、スクロールした状態で、モーダルを開いて閉じると、一番上にスクロールされた状態で表示されてしまいます。
これらを解決するCSSとJavaScriptのテクニックを紹介します。

サイトのキャプチャ

Prevent Page Scrolling When a Modal is Open


下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。

はじめに

モーダルを開いて、スクロールして、モーダルを閉じます。すると、そのページはモーダルを開いた時とは別の場所にスクロールされた状態で表示されています。

下記のデモで試してみてください。

この原因は、モーダルも他と同じようにページ上の一つの要素だからです。ページは元の位置に保持されますが(それが本来の目的だと仮定すると)、残りのページは通常通りにスクロールが動作します。

ビューポートの高さがスクリーンいっぱいであれば、問題にはなりません。しかし、そうではない場合があります。CSS(そしてJavaScript)を使用してこの問題を解決したいと思います。

簡単なことから始めましょう

body全体の高さをビューポートの高さいっぱいに定義し、モーダルが開いている時に垂直方向のオーバーフローをhiddenにすることで、このopen-modal-page-scrolling™問題に大きな影響を与えることができます。

これで問題ありませんが、モーダルを開く前にbody要素をスクロールした場合は、横方向に少しだけリフローします。ビューポートの幅は、スクロールバーの幅と同じ15pxほど広くなります。

これを避けるために、body要素に右側の余白を加えて調整します。

このテクニックを使う場合は、モーダルがビューポートの高さよりも短くなければならないことに注意してください。長い場合は、bodyのスクロールバーが必要になります。

スマホの場合

上記のテクニックは、デスクトップとAndroidのスマホで非常にうまく機能します。iOS用Safariでは、タッチスクリーンをタップして動かしているときにモーダルが開いているとbodyがスクロールするので、もう少し手を加えます。

回避策として、bodyをfixedにします。

これだけで上手く機能します! スクリーンにタッチしてもbodyは反応しません。しかし、まだ小さな問題があります。

モーダルのトリガーがページの下にあるとします。クリックして、モーダルを開くと言うでしょう。しかし、モーダルを閉じると、自動的に画面の一番上までスクロールしています。この問題は、解決しようとしているスクロールの動作と同じぐらいユーザーを混乱させます。

最初に一番下までスクロールして、それからモーダルを開いてみてください。モーダルを閉じると、一番上にスクロールされた状態になってしまいます。

この問題を解決するにはJavaScriptが必要

JavaScriptを使用すると、タッチイベントのバブルを回避できます。モーダルが開いている時には、背景レイヤーがあることは誰もが知っています。残念ながら、iOSではstopPropagationは扱いにくいですが、preventDefaultはうまく動作します。つまり、背景やモーダルボックスのレイヤーだけでなく、モーダルに含まれるすべてのDOMノードにイベントリスナーを追加する必要があります。幸いなことに、jQueryを含め、多くのJavaScriptライブラリで簡単に対応できます。

もう1つ、モーダル内をスクロールする必要がある場合はどうすればよいでしょうか。タッチイベントの応答をトリガーにしなければなりませんが、モーダルの最上部または最下部に到達した場合でも、バブリングを防ぐ必要があります。非常に複雑な作業のように見えますが、まったく問題がないわけではありません。

JavaScriptで問題を解決する

まずは、bodyに定義したCSSを見てましょう。

スクロールした位置を取得して、その位置をCSSに追加すれば、bodyはスクロールしてスクリーンの一番上まで戻ってこないので、問題は解決します。JavaScriptを使用してスクロールのトップを取得し、その値をbodyのスタイルに追加します。

これは機能しますが、モーダルが閉じられた後にも少しリークがあります。具体的には、モーダルが開いていてbodyにfixedが設定されている場合、ページはスクロール位置を失います。そのため、その位置を取得しなければなりません。JavaScriptを少し修正します。

これで完成です!
モーダルが開いている時はbodyがスクロールしなくなり、モーダルが開いている時も閉じている時もスクロール位置が維持されるようになりました。

sponsors

top of page

©2019 coliss