モーダル画面表示時や、スマホのハンバーガーメニューを開いた時に、背景スクロールを固定するライブラリを紹介します。
実現したかったこと。
- 任意のタイミングで、背景となるbody部分のスクロールを固定する
- IOS safari でも動作する
- 開いている前面のメニュー部分はスクロール可能にする
シンプルそうに見えてなかなか難しいです。
だいぶ苦戦しましたが、こちらのライブラリで実装できました。
https://github.com/willmcpo/body-scroll-lock
使い方
スマホのハンバーガーメニューを例に実装します。
HTML
ちょっと冗長になってますが…<nav> 部分がメニューです。
jsで要素を取得しやすいように、任意のIDを設定(今回は id=”nav”)
<div class="wrapper">
<nav id="nav"> // メニュー部分。IDを設定
<ul>
<li><a href="">めにゅー1</a></li>
<li><a href="">めにゅー2</a></li>
<li><a href="">めにゅー3</a></li>
<li><a href="">めにゅー4</a></li>
<li><a href="">めにゅー5</a></li>
<li><a href="">めにゅー6</a></li>
<li><a href="">めにゅー7</a></li>
<li><a href="">めにゅー8</a></li>
<li><a href="">めにゅー9</a></li>
<li><a href="">めにゅー0</a></li>
</ul>
</nav>
<div class="content">
<p class="click" id ="click"><span>click!!</span></p>
<p>some contents</p>
<p>some contents1</p>
<p>some contents2</p>
<p>some contents3</p>
<p>some contents4</p>
<p>some contents5</p>
<p>some contents6</p>
<p>some contents7</p>
<p>some contents8</p>
<p>some contents9</p>
</div>
</div>
表示は以下の動画の通り。
スタイルは割愛していますが、メニュー部分にposition: absolute; をかけ、
ボタン要素がクリックされた時に、rightの位置を戻しています。
まだ、後ろの背景はスクロールされる状態です。

メニュー要素に設定したIDで要素を取得し、bodyScrollLock に設定します。
function | 用途 |
---|---|
bodyScrollLock.disableBodyScroll( ‘hoge’ ) | ‘hoge’ 以外のスクロールを禁止 |
bodyScrollLock.clearAllBodyScrollLocks( ) | 全てのスクロール禁止を解除 |
javascript
スクロールを禁止したくない要素を設定してあげます。
最初、スクロール禁止をかけたい部分(bodyとか)を設定するのかと思ってました…
const btn = document.getElementById('click');
const nav = document.getElementById('nav');
btn.addEventListener('click' , () => {
if(nav.classList.contains('open')){
nav.classList.remove('open');
// 固定解除
bodyScrollLock.clearAllBodyScrollLocks();
} else {
nav.classList.add('open');
// 背景固定
bodyScrollLock.disableBodyScroll(nav);
}
});
上の書き方はjavascript用ですが、npm でインストールして設定する場合など
使用状況のパターンでいろいろと記述が変わってきます。
ページトップのリンクからライブラリのgitに飛べますので
ReadMeを参考にしてみてください。🙇
実装結果です。
背景は固定されていますが、前面のメニューはスクロールできます。
なかなか動画では伝わりづらいな..と思うのでぜひ実装して試してみて欲しいです。

そのうちデモぺーじもつくろうかと。多分。
上手くいかなかった試み
このライブラリを見つけるまでの戦いの記録…
もっと早く知りたかったほんとに…
Bodyにoverflow:hidden;
最も一般的な方法だと思います。iOS safari に効きません。
そこまでこだわりないのであれば、これで良いのではと思ったりします。
Scrollevent の禁止
javascriptを使ってスクロールイベントを禁止します。
safari にも有効ですが、モーダルコンテンツやメニューが長かった場合、
その部分までスクロールすることができなくなります。
スマホ横にされると短いコンテンツでもスクロールできなくなるので辛いですね…
Position fixed
こちらは、スクロール位置の情報が失われてページの1番上に戻ってしまいます。top: 〇〇pxなどで調整しても、一瞬画面にチラつきが発生します。
ライブラリ開発者の方に、感謝です。