JSでbodyのスクロール(tochmove)を止めてコンテンツ内のみスクロールできるようにする
ヘッダーメニューを開いている時に、 bodyのスクロールを無効化して、 ヘッダーメニュー内だけスクロールを有効化するときのメモ 僕はこの方法で無駄なbodyのスクロールも影響せず実装できているコードです。
const scrollLock = (scrollabletarget) => {
const scrollControl = (event) => {
if (
scrollabletarget &&
(event.target === scrollabletarget || scrollabletarget.contains(event.target))
) {
event.stopPropagation();
} else {
event.preventDefault();
}
};
const lockScroll = () => {
document.body.style.overflow = 'hidden';
document.addEventListener('touchmove', scrollControl, { passive: false });
};
const unlockScroll = () => {
document.body.style.overflow = '';
document.removeEventListener('touchmove', scrollControl, { passive: false });
};
return { lock: lockScroll, unlock: unlockScroll };
};
使い方
// 例ではheaderメニューを想定
const HeaderMenuEvent = () => {
const HeaderMenuBtn = document.getElementById('header_nav_btn');
const HeaderMenuBody = document.getElementById('header_nav_body');
const HeaderMenuScrollableContent = HeaderMenuBody.querySelector('nav');
let resizeTimer;
const ScrollLockEvent = scrollLock(HeaderMenuScrollableContent);
if (!HeaderMenuBtn || !HeaderMenuBody) { return false; }
function handleTouchMove(event) {
if (event.target === HeaderMenuBody) {
event.stopPropagation()
} else {
event.preventDefault();
}
}
HeaderMenuBtn.addEventListener('click', e => {
e.preventDefault();
HeaderMenuBtn.classList.toggle('active');
HeaderMenuBody.classList.toggle('active');
document.body.classList.toggle('header_nav_active');
if (HeaderMenuBtn.classList.contains('active')) {
ScrollLockEvent.lock();
} else {
ScrollLockEvent.unlock();
}
});
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
if (window.innerWidth >= 1025) {
HeaderMenuBtn.classList.remove('active');
HeaderMenuBody.classList.remove('active');
}
}, 300);
});
};
使い方解説
あらかじめ、開閉の動作をするJS内で
const ScrollLockEvent = scrollLock();
// または
const ScrollLockEvent = scrollLock(HeaderMenuScrollableContent);
を指定する。
この時の‘HeaderMenuScrollableContent‘は、ヘッダー内のスクロール可能なターゲットを指定しています。
指定をしていない場合はすべてのスクロール(touchmove)自体をロックするようにしています。
そして、開閉に合わせてそれぞれ
if (HeaderMenuBtn.classList.contains('active')) {
ScrollLockEvent.lock();
} else {
ScrollLockEvent.unlock();
}
と指定することでスクロールをロック・アンロックするようにしています。