body-scroll-lock.jsで特定の要素以外のスクロールをロックする方法

body-scroll-lock.jsとは

body-scroll-lock.jsを使うと特定の要素以外のスクロールをロックできる。

例えばモーダルを表示する際はモーダル内のスクロールする部分の要素以外はスクロールしないようにロックする必要がある。

body-scroll-lock.jsを使用すればスクロールをロックするための処理を簡単に実装できる。

bodyにoverflow: hiddenはiOSでは不可

これを見て「bodyにoverflow: hiddenを付ければ良いのでは?」と思う人もいるかも知れないが、bodyにoverflow: hiddenを付けるだけだとiOS (iPhoneなど)ではスクロールのロックが効かないので注意が必要。

bodyにoverflow:hiddenでスクロールロックしたサンプル

body-scroll-lock.jsの特徴

GitHubに書かれているbody-scroll-lock.jsの特徴は以下の通り。

各環境でこれらの対応をするのは手間がかかるが、body-scroll-lock.jsなら簡単に実装できる。

  • bodyのスクロールを無効化し、対象要素のスクロールを無効化しない。
  • iOSのモバイル/タブレットで動作します。
  • Androidで動作します。
  • デスクトップ版Safariで動作します。
  • Chrome/Firefoxで動作します。
  • React, Angular, VueJSで動作します。
  • ネストされたターゲット要素に対応。
  • スクロールバーの幅を確保できる。
  • -webkit-overflow-scrolling: タッチでも動作します。
body-scroll-lock.jsで特定の要素以外のスクロールをロックする方法

GitHub - willmcpo/body-scroll-lock

body-scroll-lock.jsの使い方

まず以下のコマンドでインストールする。

npm i -D body-scroll-lock

@typesが必要な場合はnpm i -D @types/body-scroll-lockも実行する

インストールしたらbody-scroll-lockからdisableBodyScrollとenableBodyScrollをimportして、以下のようにスクロールをロックする際にロックしない要素(target)を指定するだけで実装できる。

import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';

const target = document.getElementById('t');
const button = document.getElementById('b');
const modal = document.getElementById('m');
const modalBg = document.getElementById('mbg');

target.addEventListener('click', (e) => {
  e.stopPropagation();
});

button.addEventListener('click', () => {
  modal.style.display = 'flex';
  modalBg.style.display = 'block';
  disableBodyScroll(target);
});

modal.addEventListener('click', () => {
  modal.style.display = 'none';
  modalBg.style.display = 'none';
  enableBodyScroll(target);
});

body-scroll-lock.jsで特定の要素以外のスクロールをロックするサンプル