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

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


はてなブログのテーマをレスポンシブで作る際に、あれ? なぜ? と、ちょっと手間取った CSS 2題です。どちらもモバイルのメニューなど、モーダルウィンドウに関してです。



モーダルウィンドウがスクロールしない

モバイルの場合はメニューなどをモーダル、ポップアップで表示することが多いと思いますし、デスクトップでも画像をモーダルウィンドウで拡大表示したりします。


f:id:ausnichts:20180422142938j:plain

これは当サイトをモバイルで見たときの画像で、ハンバーガーメニューをクリックしモーダルウィンドウが右から出てくる途中のキャプチャーです。

で、モーダルの高さがデバイスの高さよりも長ければスクロールさせる必要があり、overflow-y: auto; を指定しますが、これだけではスクロールしません。おかしいなあ、おかしいなあといろいろやってみることしばし、わかりました。


overflow-y: auto;
height: 100%;

height も指定しないとスクロールしません。


Codepen サンプル

(注)この下に Codepen のサンプルが表示されますが、読み込みに時間がかかる場合があります。

See the Pen disable bg scroll when modal window by ausnichts (@ausnichts) on CodePen.


メニューがスクロールするようになりました。Codepenのアイコンをクリックしますと別ウィンドウで編集可能ページが開きますので、該当スタイルをコメントアウトするなりしてみてください。

ただし、iPhoneの場合はなぜかMENUアイコン自体が固定されずコンテンツと一緒にスクロールしてしまいます。これについては次項に書いています。


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

上のCodepenのサンプルのMENUをクリックしますとメニューがスライドしてきます。そのメニューをスクロールし下までいきますと、続いてモーダルの背景になっているコンテンツがスクロールしてしまいます。この背景のスクロールを止める方法です。

結論から言いますと、body要素に overflow: hidden; を指定すればスクロールは止まります。

サンプルでは、MENUのクリックイベントで body にクラス open を追加、あるいは削除し、モーダルウィンドウの表示非表示をコントロールしていますので、

body.open {
  overflow: hidden;
}

を指定すればモーダルウィンドウが開いたときだけ背景が固定されます。

ただし、デスクトップの場合、多分 android もこれで固定されますが、iPhoneはこれだけではなぜかうまくいきません。iPhoneの場合は次項です。


で、実は、背景を止める方法をいろいろ試しているうちに違う方法を発見しました。

html, body {
  overflow: auto;
  height: 100%;
}

としておけば、モーダル表示時に overflow:hidden; としなくても背景がスクロールしません。ただ、現在のところ、Codepen上だけで実装チェックしていませんので実際にそうなるかどうかは未チェックです。機会があれば調べてみようと思います。

いずれにしても、こんな簡単に固定できるなんて知りませんので、以前は背景に、サンプルですと content になりますが position:fixed; を指定し、それだけですと背景がトップに戻ってしまいますので、事前にスクロール量を取得しておき、モーダルを非表示にした時に再びその量だけスクロールさせることをやっていました。


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

iPhoneの場合は、「iPhone で iframe を fixed にする場合の問題」でも同じような問題にぶつかっており、もうひとつはっきりしたことはわかりませんが、いずれにしてもモーダルウィンドウを表示したときの挙動がデスクトップやandroidとは異なっているようです。


まず、上のCodepenのサンプルをiPhoneで見てみますと右上のMENUアイコン(もどき)がコンテンツと一緒にスクロールしてしまいます。これがCodepen上だからなのか、多分実装では経験したことがありませんのでそうだと思いますが、これを解消するには、

html, body {
  overflow: auto;
  height: 100%;
}

を指定すれば、MENUアイコンは固定されます。ただ、やはりモーダルウィンドウをスクロールさせますと背景もスクロールしていしまいます。

で、さらに、

body.open {
  overflow: hidden;
}

を指定しますと、やっとiPhoneでも背景がスクロールされなくなります。実装であれやこれや試してみるしかなさそうです。