モーダルウインドウの背景を上下にスクロールせず固定する方法

モーダルウインドウが開いた際に裏のページが上下してしまう問題、CSSだけで固定できないかと試行錯誤したのですが、iOSのSafariでどうしても挙動が安定しなかったので、とうとうJavaScriptで実装することにしました。ちょっと悔しい。

基本的な考え方

  1. 背景が固定された状態(position : fixed状態)のスタイルを作っておく
  2. モーダルの表示/非表示と、背景固定のオン/オフをJSで連動させる
  3. モーダルを表示する際に、現在のスクロール位置をJSで取得してCSSに渡す

という感じでがんばります。

HTML

  • モーダルウインドウを開く要素に、例えば class=”modalOpner” とクラスをつけておく
  • モーダルウインドウを閉じる要素に、例えば class=”modalCloser” とクラスをつけておく

CSS

背景が固定されている状態のスタイルを定義しておきます。

body.fixed {
	position: fixed;
	width: 100%;
	height: 100%;
	left: 0;
}

これで、body要素に class=”fixed” をつけたり外したりすることで背景固定のオン/オフが制御されます。
上下スクロール位置はJSで取得するので、CSSでは書いていません。

モーダルウインドウそのもののスタイルはここでは省略しています。

JavaScript

$(function(){
	var scrollPosition;
	$(".modalOpner").on("click", function() {
		scrollPosition = $(window).scrollTop();
		$('body').addClass('fixed').css({'top': -scrollPosition});
	});
	$(".modalCloser").on("click", function() {
		$('body').removeClass('fixed').css({'top': 0});
		window.scrollTo( 0 , scrollPosition );
	});
});

上記では、モーダルウインドウの表示トリガーとなる要素、例えば class=”modalOpener” がクリックされると

  • その時点でのブラウザスクロール量を取得し、
  • body に class=”fixed” をつけ、
  • body のtopプロパティにスクロール量を渡す

という処理を行います。

その結果、htmlがこうなればよいわけです。

<body style="top: -740px;" class="fixed">

もちろんですが、モーダルウインドウを非表示にする要素 class=”modalCloser” がクリックされると逆のことをします。

参考文献

サマソニのサイトの実装を参考にしました。
SUMMER SONIC TOKYO LINEUP – SUMMER SONIC 2019