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

移动端侧边栏滚动时禁止页面body滚动的实现方案

解决移动端Fixed侧边栏滚动时禁止Body滚动的方案

嘿,这个移动端fixed侧边栏的滚动冲突问题我太熟了——简直是前端开发里的经典踩坑点!我来给你一套经过实战验证的解决方案,完美解决你说的「侧边栏滚动时body跟着滚」的问题,同时保证侧边栏自身内容溢出时能正常滚动。

核心思路

要实现这个效果,我们需要做到两点:

  • 侧边栏滑出时,锁定body的滚动,但不能影响侧边栏自身的滚动
  • 处理iOS端的「滚动穿透」问题(就是你视频里展示的那种,侧边栏滚到底/顶后继续滑,body会跟着动的情况)

具体实现步骤

1. 基础CSS配置

先给侧边栏和body锁定状态做好样式铺垫:

/* 侧边栏基础样式 */
.sidebar {
  position: fixed;
  top: 0;
  left: -100%; /* 默认隐藏在左侧 */
  width: 80%; /* 可根据需求调整宽度 */
  height: 100vh;
  background-color: #fff;
  overflow-y: auto; /* 内容溢出时允许自身滚动 */
  -webkit-overflow-scrolling: touch; /* 让iOS端滚动更顺滑,避免橡皮筋滚动穿透 */
  transition: left 0.3s ease; /* 滑出/滑入的过渡动画 */
}

/* 侧边栏滑出时的状态 */
.sidebar.open {
  left: 0;
}

/* body锁定滚动的类 */
.body-locked {
  overflow: hidden;
  position: fixed;
  width: 100%; /* 避免fixed导致宽度收缩 */
}

2. JavaScript逻辑处理

接下来用JS控制侧边栏的打开/关闭,同时处理body滚动锁定和滚动穿透问题:

// 获取DOM元素
const sidebar = document.querySelector('.sidebar');
const openSidebarBtn = document.querySelector('.open-sidebar-btn');
const closeSidebarBtn = document.querySelector('.close-sidebar-btn');

// 记录打开侧边栏前的页面滚动位置
let preScrollTop = 0;

// 打开侧边栏的逻辑
openSidebarBtn.addEventListener('click', () => {
  // 保存当前滚动位置,避免锁定body后页面跳回顶部
  preScrollTop = window.pageYOffset || document.documentElement.scrollTop;
  
  // 给body添加锁定类,并设置top值抵消滚动位置变化
  document.body.classList.add('body-locked');
  document.body.style.top = `-${preScrollTop}px`;
  
  // 滑出侧边栏
  sidebar.classList.add('open');
  
  // 添加滚动穿透阻止监听
  sidebar.addEventListener('touchmove', preventScrollThrough, { passive: false });
});

// 关闭侧边栏的逻辑
closeSidebarBtn.addEventListener('click', () => {
  // 移除body锁定类,恢复默认样式
  document.body.classList.remove('body-locked');
  document.body.style.top = '';
  
  // 滑入侧边栏
  sidebar.classList.remove('open');
  
  // 移除滚动穿透监听
  sidebar.removeEventListener('touchmove', preventScrollThrough);
  
  // 回到打开侧边栏前的滚动位置
  window.scrollTo(0, preScrollTop);
});

// 阻止滚动穿透的核心函数
function preventScrollThrough(e) {
  const isScrollTop = sidebar.scrollTop === 0;
  const isScrollBottom = sidebar.scrollHeight - sidebar.scrollTop === sidebar.clientHeight;
  
  // 当侧边栏已经滚到顶部/底部时,阻止默认触摸滚动事件,避免触发body滚动
  if ((isScrollTop && e.deltaY < 0) || (isScrollBottom && e.deltaY > 0)) {
    e.preventDefault();
  }
}

关键细节说明

  • -webkit-overflow-scrolling: touch:这个属性是iOS端的关键,它会让侧边栏使用原生滚动效果,不仅更顺滑,还能减少滚动穿透的概率。
  • 记录滚动位置:直接给body加overflow: hidden会导致页面跳回顶部,所以我们要先保存滚动位置,关闭侧边栏后再恢复回去。
  • 滚动穿透阻止函数:当侧边栏已经滚到边界时,阻止默认的触摸事件,彻底避免body跟着滚动的情况。

兼容性说明

这套方案兼容绝大多数移动端浏览器,包括iOS Safari和Android各大浏览器。如果你的项目不需要兼容太老的浏览器,也可以尝试用overscroll-behavior: contain属性直接给侧边栏设置,但这个属性在一些旧设备上支持不佳,所以上面的方案更稳妥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:55:57