使用 overflow: hidden (最常用、最简单)
这是最直接、最常用的方法,通过给 body 元素设置 overflow: hidden,可以禁止整个页面的滚动条出现。

如何实现?
在需要禁止滚动的时机(打开模态框时),向 body 添加一个类,no-scroll,并定义这个类的样式。
CSS 定义
.no-scroll {
/* 禁止页面滚动 */
overflow: hidden;
/* 可选:防止页面在iOS上仍能轻微滚动 */
position: fixed;
/* 为了防止页面因position: fixed而跳动,需要设置一个与视口高度相等的宽度 */
width: 100vw;
/* 为了防止页面因position: fixed而跳动,需要设置一个与视口高度相等的高度 */
height: 100vh;
}
JavaScript 操作
当需要禁止滚动时:

document.body.classList.add('no-scroll');
当需要恢复滚动时:
document.body.classList.remove('no-scroll');
优点
- 简单直接:CSS 原生属性,易于理解和实现。
- 兼容性好:在所有现代浏览器中都表现良好。
缺点
- 页面跳动:当
overflow: hidden生效时,滚动条会消失,导致页面内容宽度突然增加(等于滚动条的宽度),页面会向左“跳动”一下,虽然position: fixed; width: 100vw; height: 100vh;可以在很大程度上缓解这个问题,但在某些复杂布局下仍可能产生细微影响。 - 滚动位置丢失:如果用户已经滚动了一部分页面,然后禁止滚动,再恢复时,页面会“跳”回顶部,这是因为
position: fixed会将元素相对于视口定位,脱离了正常的文档流。
使用 preventDefault() (更精细的控制)
通过监听 touchmove 和 wheel 事件,并在事件处理函数中调用 event.preventDefault(),可以阻止事件的默认行为,从而阻止滚动。
如何实现?
禁止滚动
// 禁用鼠标滚轮
function preventScroll(e) {
e.preventDefault();
}
// 禁用触摸移动(移动端)
function preventTouchMove(e) {
e.preventDefault();
}
// 添加事件监听
document.addEventListener('wheel', preventScroll, { passive: false });
document.addEventListener('touchmove', preventTouchMove, { passive: false });
// body的样式可以不加,但加上可以防止页面跳动
document.body.style.overflow = 'hidden';
恢复滚动
// 移除事件监听
document.removeEventListener('wheel', preventScroll);
document.removeEventListener('touchmove', preventTouchMove);
// 恢复body的样式
document.body.style.overflow = '';
重要提示:{ passive: false }
在调用 addEventListener 时,必须设置 passive: false,这是因为现代浏览器为了提升滚动性能,默认将 touchmove 和 wheel 事件监听器设为 passive: true,这意味着你不能在事件处理函数中调用 preventDefault(),浏览器会忽略它并抛出警告。passive: false 告诉浏览器:“我可能会调用 preventDefault(),请先等待,不要优化滚动”。
优点
- 无页面跳动:因为滚动条本身还在,只是被禁用了,所以不会出现宽度变化导致的跳动。
- 保留滚动位置:恢复滚动时,页面会停留在之前的位置。
缺点
- 实现稍复杂:需要手动添加和移除事件监听器。
- 可能影响性能:
preventDefault的处理逻辑复杂,可能会对滚动性能产生轻微影响(尽管通常不明显)。
结合 position: fixed 和 scrollTop (解决位置丢失问题)
这是对方法一的优化,完美解决了“页面跳动”和“滚动位置丢失”两个问题。
原理
- 在禁止滚动前,记录当前页面的滚动位置 (
scrollTop)。 - 给
body设置position: fixed和top值(值为负的滚动位置),这会把整个页面“钉”在当前位置,即使没有滚动条,视觉上也不会跳动。 - 当恢复滚动时,移除
position: fixed,并将页面滚动回之前记录的位置。
如何实现?
// 存储滚动位置的变量
let scrollPosition = 0;
function disableScroll() {
// 1. 记录当前滚动位置
scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
// 2. 给body添加样式,固定页面
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollPosition}px`;
document.body.style.width = '100%'; // 防止内容挤压
}
function enableScroll() {
// 1. 移除body的固定样式
document.body.style.position = '';
document.body.style.top = '';
document.body.style.width = '';
// 2. 滚动回之前记录的位置
window.scrollTo(0, scrollPosition);
}
// 使用示例
// 打开模态框时
disableScroll();
// 关闭模态框时
enableScroll();
优点
- 完美解决所有问题:既没有页面跳动,也保留了滚动位置,兼容性也很好。
- 用户体验最佳:这是目前最推荐的方案,尤其是在需要频繁开关滚动的场景下。
缺点
- 代码量稍多:需要额外的逻辑来记录和恢复滚动位置。
总结与推荐
| 方法 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
overflow: hidden |
简单、快速 | 页面跳动、滚动位置丢失 | 简单的、一次性的弹窗,对跳动不敏感的场景。 |
preventDefault() |
无跳动、保留位置 | 代码稍复杂、需注意 passive: false |
需要精细控制、不能有页面跳动的场景。 |
position: fixed + scrollTop |
无跳动、保留位置、兼容性好 | 代码量稍多 | 强烈推荐,特别是移动端、复杂页面、或需要多次开关滚动的场景。 |
最终建议:
对于绝大多数项目,特别是追求良好用户体验的项目,强烈推荐使用方法三 (position: fixed + scrollTop),它虽然代码多几行,但完美解决了核心痛点,是专业且健壮的解决方案。
如果你的项目非常简单,或者只是一个临时的演示,并且不介意页面跳动,那么方法一 (overflow: hidden) 也是一个快速的选择。
