如何在滚动固定div时禁用body滚动且保留其滚动条
如何在滚动固定定位元素时禁用body滚动但保留滚动条
这确实是个挺常见的痛点——用overflow: hidden虽然能快速阻止body滚动,但滚动条突然消失导致页面抖动的体验真的很差。下面分享两种经过实践验证的方案,既能搞定body滚动拦截,又能保留滚动条,完美避免页面跳动:
方法一:通过事件监听精准拦截body滚动
这种方法的核心思路是:当固定定位的div(比如弹窗、侧边栏)处于可滚动状态时,捕获body上的各类滚动事件并阻止默认行为,关闭时再恢复正常。
代码示例
// 标记固定元素的激活状态 let isFixedElementActive = false; // 定义阻止滚动的通用函数 function stopBodyScroll(e) { e.preventDefault(); } // 开启固定元素时,启动滚动拦截 function activateFixedElement() { isFixedElementActive = true; // 阻止鼠标滚轮滚动 document.body.addEventListener('wheel', stopBodyScroll, { passive: false }); // 阻止移动端触摸滚动 document.body.addEventListener('touchmove', stopBodyScroll, { passive: false }); // 可选:阻止键盘方向键/翻页键滚动 document.body.addEventListener('keydown', (e) => { const scrollKeys = [33, 34, 35, 36, 38, 40]; // PageUp、PageDown、End、Home、上下箭头 if (scrollKeys.includes(e.keyCode)) { e.preventDefault(); } }); } // 关闭固定元素时,解除滚动拦截 function deactivateFixedElement() { isFixedElementActive = false; document.body.removeEventListener('wheel', stopBodyScroll); document.body.removeEventListener('touchmove', stopBodyScroll); document.body.removeEventListener('keydown', stopBodyScroll); }
关键注意点
一定要设置{ passive: false },因为现代浏览器为了性能优化,默认会把wheel、touchmove这类事件设为passive: true,此时preventDefault()会被忽略,导致拦截失效。
方法二:CSS+JS组合,保留滚动条同时锁定页面
如果希望滚动条始终显示(哪怕body不能滚动),可以用这种方法:通过CSS强制显示滚动条,再用JS计算滚动条宽度抵消页面宽度变化,最后配合事件拦截阻止滚动。
步骤1:计算滚动条宽度
先写一个工具函数获取当前浏览器的滚动条宽度:
function getScrollbarWidth() { const tempDiv = document.createElement('div'); tempDiv.style.width = '100px'; tempDiv.style.height = '100px'; tempDiv.style.overflow = 'scroll'; tempDiv.style.position = 'absolute'; tempDiv.style.top = '-9999px'; // 隐藏到视野外 document.body.appendChild(tempDiv); const scrollbarWidth = tempDiv.offsetWidth - tempDiv.clientWidth; document.body.removeChild(tempDiv); return scrollbarWidth; }
步骤2:启用/关闭滚动拦截
function activateFixedElement() { const scrollbarWidth = getScrollbarWidth(); // 强制显示body滚动条 document.body.style.overflowY = 'scroll'; // 添加padding抵消滚动条宽度,避免页面抖动 document.body.style.paddingRight = `${scrollbarWidth}px`; // 再配合事件拦截阻止实际滚动 document.body.addEventListener('wheel', stopBodyScroll, { passive: false }); document.body.addEventListener('touchmove', stopBodyScroll, { passive: false }); } function deactivateFixedElement() { // 恢复body原始样式 document.body.style.overflowY = ''; document.body.style.paddingRight = ''; // 移除事件监听 document.body.removeEventListener('wheel', stopBodyScroll); document.body.removeEventListener('touchmove', stopBodyScroll); }
优势
这种方法既能让滚动条一直保持显示,又能彻底阻止body滚动,同时完全避免了页面抖动的问题,适合对视觉一致性要求较高的场景。
内容的提问来源于stack exchange,提问作者albardn2
相关产品推荐
相关产品推荐

