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

如何在不改变窗口尺寸的情况下正确启用和禁用页面滚动

解决弹窗时阻止页面滚动且不改变窗口尺寸的问题

嘿,这个坑我之前做项目的时候也踩过好几次!切换bodyoverflow属性时,滚动条突然消失/出现导致页面跳一下,真的很破坏用户体验。给你分享几个亲测有效的解决方案,按需选择:

方法1:固定body定位+保留滚动位置(最推荐)

核心思路是用position: fixed让页面无法滚动,同时记录当前的滚动位置,关闭弹窗时恢复。这样滚动条的占位会被保留,页面不会出现尺寸变化。

实现代码:

// 打开弹窗的逻辑
function openModal() {
  // 记录当前滚动距离
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  // 固定body,禁止滚动
  document.body.style.position = 'fixed';
  document.body.style.width = '100%';
  document.body.style.top = `-${scrollTop}px`;
  // 这里加上显示弹窗的代码
}

// 关闭弹窗的逻辑
function closeModal() {
  // 取出之前记录的滚动距离
  const scrollTop = parseInt(document.body.style.top || '0');
  // 恢复body的默认状态
  document.body.style.position = '';
  document.body.style.width = '';
  document.body.style.top = '';
  // 滚回原来的位置
  window.scrollTo(0, scrollTop);
  // 这里加上隐藏弹窗的代码
}

为什么这么做?固定定位会让body脱离文档流,自然无法滚动;设置width:100%避免宽度收缩;top设为负的滚动距离,能保证页面不会突然跳到顶部,体验更自然。

方法2:用padding-right抵消滚动条宽度

如果你还是想用overflow: hidden的方式,那可以先计算出浏览器滚动条的宽度,打开弹窗时给body加上对应宽度的padding-right,抵消滚动条消失带来的宽度变化。

实现代码:

// 计算滚动条宽度的工具函数
function getScrollbarWidth() {
  const outer = document.createElement('div');
  outer.style.visibility = 'hidden';
  outer.style.width = '100px';
  outer.style.msOverflowStyle = 'scrollbar'; // 兼容IE
  document.body.appendChild(outer);

  const widthNoScroll = outer.offsetWidth;
  outer.style.overflow = 'scroll';

  const inner = document.createElement('div');
  inner.style.width = '100%';
  outer.appendChild(inner);

  const widthWithScroll = inner.offsetWidth;
  outer.parentNode.removeChild(outer);

  return widthNoScroll - widthWithScroll;
}

// 打开弹窗
function openModal() {
  const scrollbarWidth = getScrollbarWidth();
  document.body.style.overflow = 'hidden';
  document.body.style.paddingRight = `${scrollbarWidth}px`;
  // 注意:如果页面有固定定位的元素(比如导航栏),也要给它们加同样的padding-right
  // document.querySelector('.navbar').style.paddingRight = `${scrollbarWidth}px`;
}

// 关闭弹窗
function closeModal() {
  document.body.style.overflow = '';
  document.body.style.paddingRight = '';
  // 恢复固定元素的padding-right
  // document.querySelector('.navbar').style.paddingRight = '';
}

这个方法的缺点是需要处理页面中固定定位的元素,不然这些元素会因为body的padding-right而移位,增加了一点额外的工作量。

方法3:强制显示滚动条(最简单但视觉上有取舍)

直接给body默认设置overflow-y: scroll,这样不管页面内容有没有超出,滚动条都会一直显示。此时切换overflow: hidden时,页面宽度不会发生变化,因为滚动条的占位一直在。

CSS代码:

body {
  overflow-y: scroll;
}

然后弹窗打开/关闭时还是用你原来的逻辑:

// 打开弹窗
document.body.style.overflow = 'hidden';
// 关闭弹窗
document.body.style.overflow = 'scroll';

这个方法的优点是代码最简单,但如果页面内容较短,会显示空的滚动条,可能不符合某些设计风格,适合对视觉要求没那么严格的场景。


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

火山引擎 最新活动