长页面显示弹窗时禁用滚动且保留滚动条的可行方案咨询
解决弹窗时禁用页面滚动且避免跳顶的方案
嘿,我完全懂你遇到的这个痛点!弹窗弹出时禁用页面滚动本来是个常见需求,但那两个方案确实都有坑——一个跳顶毁体验,另一个只处理鼠标滚轮还不够全面。我给你调整一下这两个方案,让它们完美满足需求:
方案一:修复fixed导致的跳顶问题
你原来的思路没问题,只是没保存当前滚动位置。设置position: fixed时,浏览器会把页面定位到视口顶部,所以我们要先记录滚动距离,再通过top属性把页面“固定”在原来的位置:
打开弹窗时执行:
// 先获取当前页面滚动的距离 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; // 固定body,同时通过top值保持原滚动位置 document.body.style.position = 'fixed'; document.body.style.top = `-${scrollTop}px`; document.body.style.width = '100%'; // 避免fixed导致body宽度收缩 document.body.style.overflowY = 'scroll';
关闭弹窗时恢复:
// 取出之前保存的滚动距离 const scrollTop = parseInt(document.body.style.top) * -1; // 还原body的样式 document.body.style.position = ''; document.body.style.top = ''; document.body.style.width = ''; document.body.style.overflowY = ''; // 滚动到原来的位置 window.scrollTo(0, scrollTop);
这样既禁用了页面滚动,又不会出现跳顶的问题,兼容性也很好。
方案二:补全所有滚动相关事件的阻止
你原来的mousewheel监听只覆盖了桌面端的鼠标滚轮,还得处理移动端的触摸滚动、键盘的滚动操作(比如上下箭头、空格、PageUp/PageDown),而且记得弹窗关闭时要移除监听,不然页面一直不能滚动:
步骤1:定义阻止滚动的通用函数
function preventScroll(e) { e.preventDefault(); } // 单独处理键盘事件的函数 function preventKeyboardScroll(e) { // 需要阻止的按键:上箭头(38)、下箭头(40)、空格(32)、PageUp(33)、PageDown(34) const forbiddenKeys = [38, 40, 32, 33, 34]; if (forbiddenKeys.includes(e.keyCode)) { e.preventDefault(); } }
步骤2:打开弹窗时添加监听
// 鼠标滚轮事件 document.body.addEventListener('mousewheel', preventScroll, { passive: false }); // 移动端触摸滚动事件,passive: false必须加,不然preventDefault可能失效 document.body.addEventListener('touchmove', preventScroll, { passive: false }); // 键盘滚动事件 document.addEventListener('keydown', preventKeyboardScroll);
步骤3:关闭弹窗时移除监听
document.body.removeEventListener('mousewheel', preventScroll); document.body.removeEventListener('touchmove', preventScroll); document.removeEventListener('keydown', preventKeyboardScroll);
这个方案不会改变body的布局,但需要处理更多事件,适合对页面布局有严格要求的场景。
方案选择建议
- 如果你的项目兼容大部分现代浏览器,方案一调整后更简洁,代码量少且不容易漏事件;
- 如果需要避免修改body的position属性,或者要处理一些特殊布局场景,方案二补全事件后更稳妥。
内容的提问来源于stack exchange,提问作者gyc
相关产品推荐
相关产品推荐

