「モーダルを開いたときに背景を固定して!」とお願いされたら
対応する機会が多い仕様ではないですが、忘れたころにやってくるこのお願い。
「昔やった気がするけど、ちょっとややこしかったような…」
と不安になる方も多いはず。
これ、CSSだけで対応しようとすると失敗するんです。
しかしポイントさえ押さえてしまえば、割と簡単に対処できます。
急な依頼でも慌てることがないように、解決法を見ていきましょう。
【基本コード】モーダルの背景を固定しよう
JavaScript
//変数の設定
var $body = $('body');
//スクロール量を保存
var scrollTop;
//スクロールを固定
function bodyFixedOn() {
scrollTop = $(window).scrollTop();
$body.css({
position: 'fixed',
top: -scrollTop
});
}
//スクロールの固定を解除
function bodyFixedOff() {
$body.css({
position: '',
top: ''
});
$(window).scrollTop(scrollTop);
}
//モーダルのトリガーをクリックしたとき
$('.modal-trigger').on('click', function() {
bodyFixedOn();
});
//モーダルの閉じるボタンをクリックしたとき
$('.modal-close').on('click', function() {
bodyFixedOff();
});
//モーダルのオーバーレイをクリックしたとき
$('.overlay').on('click', function() {
bodyFixedOff();
});
HTML
<!-- モーダルを開くボタン -->
<a class="modal-trigger" href="#">
モーダルを開く
</a>
<!-- モーダル本体 -->
<div class="modal-wrap">
<div class="overlay"></div>
<div class="modal-inner">
<div class="img">
モーダルが開きました。<br>背景も固定されました。
</div>
<button class="modal-close">×</button>
</div>
<!-- /.modal-inner -->
</div>
<!-- /.modal-wrap -->
SCSS
.modal-wrap{
position: fixed;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100vh;
opacity: 0;
visibility: hidden;
transition: opacity .3s linear, visibility .3s linear;
z-index: -1;
.overlay{
position: fixed;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .8);
cursor: pointer;
}
.modal-inner{
position: absolute;
top: 50%;
left: 50%;
width: 100%;
background: rgba(255, 255, 255, .8);
transform: translate(-50%, -50%);
.modal-close{
position: absolute;
cursor: pointer;
}
}
&.show{
opacity: 1;
visibility: visible;
z-index: 10000;
}
}
@media screen and (min-width: 768px) {
.modal-trigger{
transition: opacity .3s linear;
}
.modal-wrap{
.modal-inner{
max-width: 960px;
.modal-close{
top: -48px;
right: 0;
}
}
}
}
@media screen and (max-width: 767px) {
.modal-wrap{
.modal-inner{
width: 90%;
.modal-close{
top: -30px;
right: 0;
}
}
}
}
こんな感じでしょうか。
HTMLやCSSはデザインに合わせて調整してください。
【Demo】モーダルの背景を固定しよう
See the Pen bodyFIxed by Yusuke Saio (@saio-th) on CodePen.
【Point】モーダルの背景を固定しよう
- スクロール量を取得する
- モーダルを開くときはスクロール量を「CSS」で
body
要素に設定する - モーダルを閉じるときはスクロール量を「JavaScript」で
window
オブジェクトに設定する
【解説】モーダルの背景を固定しよう
細かくコードを見ていきましょう。
詳細に説明するために、一部上記で紹介したものと異なるコードが出てきます。
実際に使用するときは「基本コード」を参考にしてください。
スクロール量を取得
スクロールの固定は「スクロール量」を指定したり解除したりすることで実現します。
ということで、まずはスクロール量を取得しましょう。
スクロール量は$(window).scrollTop()
メソッドで取得できます。
「モーダルウィンドウを開く」ボタンをクリックしたときに取得してください。
//例
$('.modal-trigger').on('click', function() {
scrollTop = $(window).scrollTop();
});
モーダルが開いたらbody要素を固定して、CSSでスクロール量を設定する
次に、スクロールを固定する処理を実装します。
具体的には以下の処理をほどこします。
body
要素をposition: fixed;
で固定するbody
要素の位置を、スクロール量分上にずらす
こうすることで、モーダルを開く前後で背景がズレません。
//例
$('.modal-trigger').on('click', function() {
scrollTop = $(window).scrollTop();
$('body').css({
position: 'fixed',
top: -scrollTop
});
});
top
プロパティにスクロール量を指定しないとどうなるでしょうか。
モーダルを開いた瞬間に背景がページの一番上に戻ってしまいます。
以下に図を用意したのでご覧ください。

図で説明した原理で、スクロールが固定されます。
ポイントは、
「モーダルを開いた時に、CSSでスクロール量を指定する」
です。
モーダルを閉じたらbody要素の固定を解除して、JavaScriptでwindowオブジェクトにスクロール量を設定する
最後に、「モーダルを閉じるボタン」やオーバーレイをクリックした時に固定を解除する処理を実装します。
body
要素に指定したCSSを解除するwindow
オブジェクトにモーダルオープン時に取得したスクロール量を指定する
これでモーダルを開く前の状態に戻すことができます。
//例
$('.modal-close').on('click', function() {
$('body').css({
position: '',
top: ''
});
$(window).scrollTop(scrollTop);
});
上記コードの通り、window
オブジェクトにスクロール量を設定するのにも、scrollTop()
メソッドを使用します。scrollTop()
メソッドの引数に数値を入れると、スクロール量を指定することができます。
以上で一連の流れが完了です。
【まとめ】モーダルの背景を固定しよう
昔私が失敗した原因は、取得したスクロール量をCSSだけで制御しようとしたことです。
大切なのは、
「開くときは、スクロール量をCSSで指定」
「閉じるときは、スクロール量をJavaScriptで指定
」
すること!!
以上です。
少しでもお役に立てたら幸いです。
参考サイト
■モーダルを開いている時にページがスクロールしてしまうのを防ぐCSSとJavaScriptのテクニック
https://coliss.com/articles/build-websites/operation/javascript/prevent-page-scrolling-when-a-modal-is-open.html
Comments