You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JS打开菜单时禁止页面滚动,如何避免内容跳转问题?

解决菜单打开时设置overflow-y: hidden导致内容跳转的问题

嘿,这个问题我之前也碰到过好几次!当你给body设置overflow-y: hidden时,浏览器会移除垂直滚动条,页面的可用宽度突然变宽,就导致了内容“跳”的现象。下面给你几个靠谱的解决办法,你可以根据项目需求选:

方法1:用padding抵消滚动条宽度

核心思路是先计算出浏览器滚动条的宽度,然后在隐藏滚动条时给body(以及页面中的固定定位元素)添加对应宽度的右侧padding,填补滚动条消失后的空间,让页面整体宽度保持不变。

首先写一个获取滚动条宽度的工具函数:

function getScrollbarWidth() {
  const scrollDiv = document.createElement('div');
  // 设置样式让元素产生滚动条
  scrollDiv.style.width = '100px';
  scrollDiv.style.height = '100px';
  scrollDiv.style.overflow = 'scroll';
  scrollDiv.style.position = 'absolute';
  scrollDiv.style.top = '-9999px'; // 隐藏到视口外
  document.body.appendChild(scrollDiv);
  // 计算滚动条宽度:元素整体宽度 - 内容区域宽度
  const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  document.body.removeChild(scrollDiv);
  return scrollbarWidth;
}

然后在菜单打开/关闭时调用:

// 打开菜单
function openMenu() {
  const scrollbarWidth = getScrollbarWidth();
  document.body.style.overflowY = 'hidden';
  // 给body加padding抵消滚动条宽度
  document.body.style.paddingRight = `${scrollbarWidth}px`;
  
  // 如果页面有固定定位的元素(比如顶部导航栏),也要同步添加padding
  const fixedElements = document.querySelectorAll('.fixed-element');
  fixedElements.forEach(el => {
    el.style.paddingRight = `${scrollbarWidth}px`;
  });
}

// 关闭菜单
function closeMenu() {
  document.body.style.overflowY = '';
  document.body.style.paddingRight = '';
  
  // 恢复固定元素的padding
  const fixedElements = document.querySelectorAll('.fixed-element');
  fixedElements.forEach(el => {
    el.style.paddingRight = '';
  });
}

方法2:用position: fixed替代overflow-y: hidden

如果你的菜单是全屏覆盖式的,可以试试这个方法:把body设置为position: fixed,让它固定在视口内,这样页面自然无法滚动,同时因为body宽度保持100%,不会出现滚动条消失导致的宽度变化。需要注意记录当前滚动位置,关闭菜单后恢复。

let scrollPosition = 0;

// 打开菜单
function openMenu() {
  // 记录当前滚动的位置
  scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
  document.body.style.position = 'fixed';
  document.body.style.top = `-${scrollPosition}px`;
  document.body.style.width = '100%';
}

// 关闭菜单
function closeMenu() {
  document.body.style.position = '';
  document.body.style.top = '';
  // 恢复到之前的滚动位置
  window.scrollTo(0, scrollPosition);
}

方法3:使用CSS新属性scrollbar-gutter: stable

这是最简洁的方法,适合只需要支持现代浏览器的项目。scrollbar-gutter属性可以让浏览器提前预留出滚动条的空间,即使滚动条不存在,页面宽度也不会变化。

直接给body添加CSS样式:

body {
  scrollbar-gutter: stable both;
}

之后你只需要在菜单打开时设置document.body.style.overflowY = 'hidden',关闭时恢复即可,不需要额外处理宽度问题。

注意:这个属性兼容性不错,但IE等旧版浏览器不支持,如果你的项目需要兼容旧浏览器,建议用前两种方法。

内容的提问来源于stack exchange,提问作者al al

火山引擎 最新活动