You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在滚动固定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:52:04