Webサイトでモーダルウィンドウを開いたとき、背景がスクロールできてしまって困ったことはありませんか?
Webサイトでモーダルを表示する場面はよくありますが、その際に、背景(=body全体)のスクロールを固定しないと、ユーザーにとって操作しづらくなってしまうことがあります。
この記事では、以下の内容をサンプルコードを用いてわかりやすく解説します。
- 背景のスクロール固定が必要な理由
- 背景のスクロールを固定する方法
overflow: hidden;
を使ってスクロールを止めるposition: fixed;
を使って背景を固定し、モーダルを開いた地点のスクロール量をズラす
背景のスクロール固定が必要な理由
モーダルを開いたときに、背景(=body全体)がスクロールできてしまうと、次のような問題が発生します。
- ユーザーが意図せず背景をスクロールしてしまう
- モーダル内のスクロールと競合し、誤操作が発生する
このように、スクロールが意図しない動作を生むことが多いため、モーダルの操作に集中してもらうためには、背景のスクロールはしっかり固定すべきであると考えられます。
背景のスクロールを固定する方法
overflow: hidden;を使ってスクロールを止める
もっとも一般的でシンプルな方法が、body
にoverflow: hidden;
を付ける方法です。
メリット
- 実装が非常に簡単
デメリット
- Windowsなどでスクロールバーが常時表示の場合、スクロール固定時に画面がスクロールバーの幅の分だけ横にガタつく
サンプルコードを以下に示します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>モーダルのスクロール固定(overflow: hidden;)</title>
<style>
body {
overflow-y: scroll; /* スクロールバーを適用 */
margin: 0;
}
.content {
height: 200vh; /* スクロールできるように */
background: lightgray;
padding: 20px;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
max-width: 400px;
background: white;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
display: none;
z-index: 1000;
}
/* bodyスクロール固定用 */
.modal-open {
overflow: hidden;
}
</style>
</head>
<body>
<div class="content">
<button onclick="openModal()">モーダルを開く</button>
</div>
<div class="modal">
<p>モーダルウィンドウ</p>
<button onclick="closeModal()">閉じる</button>
</div>
<script>
function openModal() {
document.body.classList.add('modal-open'); // bodyにスクロール固定用のクラスを追加
document.querySelector('.modal').style.display = 'block'; // モーダルを開く
}
function closeModal() {
document.body.classList.remove('modal-open'); // スクロール固定用のクラスを削除
document.querySelector('.modal').style.display = 'none'; // モーダルを閉じる
}
</script>
</body>
</html>
この方法は、実装が非常に簡単ですが、スクロール固定時に画面がスクロールバーの幅の分だけ横にガタつくのが問題です。これが気になる人はスクロールの固定にposition: fixed
を使うと、ガタつき問題を解消することができます。
position: fixed;を使って背景を固定し、モーダルを開いた地点のスクロール量をズラす
もう一つの方法は、bodyにposition: fixed;
を指定して画面そのものを固定する方法です。
メリット
- スクロールバーによるガタつきを防げる
デメリット
window.scrollTo
などを使って元のスクロール位置に戻すロジックが必要
サンプルコードを以下に示します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>モーダルのスクロール固定(position: fixed;)</title>
<style>
body {
overflow-y: scroll; /* スクロールバーを適用 */
margin: 0;
}
.content {
height: 200vh; /* スクロールできるように */
background: lightgray;
padding: 20px;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
max-width: 400px;
background: white;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
display: none;
z-index: 1000;
}
/* bodyスクロール固定用 */
.modal-open {
width: 100%;
position: fixed;
left: 0;
}
</style>
</head>
<body>
<div class="content">
<button onclick="openModal()">モーダルを開く</button>
</div>
<div class="modal">
<p>モーダルウィンドウ</p>
<button onclick="closeModal()">閉じる</button>
</div>
<script>
let scrollPosition = 0; // スクロール位置を保存する変数
function openModal() {
scrollPosition = window.pageYOffset; // 現在のスクロール位置を取得して保存
document.body.classList.add('modal-open'); // bodyにスクロール固定用のクラスを追加
document.body.style.top = `-${scrollPosition}px`; // topプロパティでスクロール位置を固定
document.querySelector('.modal').style.display = 'block'; // モーダルを開く
}
function closeModal() {
document.body.classList.remove('modal-open'); // スクロール固定用のクラスを削除
document.body.style.top = ''; // topプロパティでスクロール位置を固定したのをリセットする
window.scrollTo(0, scrollPosition); // モーダルを開く前のスクロール位置に戻す
document.querySelector('.modal').style.display = 'none'; // モーダルを閉じる
}
</script>
</body>
</html>
body
にposition: fixed;
を指定すると、スクロールが完全に無効化されるため、すべてのブラウザで確実にスクロールを固定できます。しかしこのとき、body
の中身によってはレイアウトが崩れることがあります。特に横幅が狭くなってしまう場合があるので、保険としてwidth: 100%;
を併せて指定しておくのがおすすめです。
また、position: fixed;
を使うと、ページのスクロール位置がリセットされ、画面が一番上に戻ってしまうという問題が発生します。これを防ぐために、モーダルを「開く時」と「閉じる時」において、以下のような対処を行う必要があります。
モーダルを「開く時」
- モーダルを開く前に、現在のスクロール位置を取得して保存する。
position: fixed;
を設定する。body
のtop
プロパティにtop: -スクロール量px
を指定し、見た目上は元の位置にいるように見せかける。
モーダルを「閉じる時」
position: fixed;
を解除する。body
のtop
プロパティでスクロール位置を固定したのをリセットするwindow.scrollTo
等でモーダルを開く前のスクロール位置に戻す
本記事のまとめ
この記事では『背景(=body全体)のスクロールを固定する方法』について、以下の内容を説明しました。
- 背景のスクロール固定が必要な理由
- 背景のスクロールを固定する方法
overflow: hidden;
を使ってスクロールを止めるposition: fixed;
を使って背景を固定し、モーダルを開いた地点のスクロール量をズラす
お読み頂きありがとうございました。