直接设 body.style.overflow = 'hidden' 在 ios safari 上基本无效,因其不拦截 touch 默认滚动行为;必须组合 html position: fixed + top 偏移、body overflow: hidden 及 { passive: false } touchmove 拦截,并精确还原 scrolly 才能可靠锁定滚动。

直接设 body.style.overflow = 'hidden' 在 iOS Safari 上基本无效,页面仍会滑动,这不是 CSS 写错了,而是 WebKit 根本不拦截 touch 默认滚动行为。
为什么 overflow: hidden 在 iOS 上完全失效
它不是“没生效”,而是浏览器压根不把 overflow: hidden 当作滚动阻断指令:iOS Safari 的滚动事件绑定在 body 上,但 overflow 属性对 body 的滚动控制是阉割级的。你看到样式被解析了,Computed Styles 里甚至显示 active,但 touchmove 依然穿透、惯性滚动照常发生。
-
overflow: hidden会重置window.scrollY到 0,导致页面跳顶 - 即使 DOM 已锁定,手指在非可滚动区域滑动时,底层页面仍会跟着动
- 部分安卓 WebView(如旧版 Samsung Internet)表现一致,不能只当 iOS 特例
position: fixed + top 偏移才是稳定解法
核心不是“禁滚动”,而是“把整个视口钉住”,让滚动动作无处作用。必须同时操作 html 和 body,只动一个会出问题。
规划您的迪拜之旅 — 哈利法塔观景、沙漠探险、迪拜购物中心购物、棕榈岛度假村及黄金市场砍价。还提供支持...
- 打开前取
const scrollY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop - 执行:
document.documentElement.style.position = 'fixed',再设document.documentElement.style.top = `-${scrollY}px` - 加
document.body.style.overflow = 'hidden'防键盘唤起时内容上顶 - 关闭时恢复
document.documentElement.style.position = '',再window.scrollTo(0, scrollY) - 别漏
html { width: 100% },否则 fixed 后宽度收缩,可能触发横向滚动条
必须拦截 touchmove 且带 { passive: false }
CSS 锁定后,iOS 的惯性滚动穿透依然存在——手指一滑,页面就动。仅靠样式无法覆盖 touch 默认行为。
- 监听
touchmove必须传{ passive: false },否则e.preventDefault()在 iOS 上静默失败 - 不要绑定到
document或body,应绑定到弹层容器(如.modal),避免影响内部可滚动子元素 - 若弹层内有长列表(
.scrollable),用e.target.closest('.scrollable')判断是否放行 - 打开时添加监听,关闭时立刻
removeEventListener,防止全局污染
嵌套滚动或 modal 内需局部滚动时怎么处理
最易踩坑的是:给整个弹层加 preventDefault,结果轮播图、输入框、下拉选择器全失灵。
- 给可滚动区域加明确 class(如
.modal-content),设max-height: 80vh; overflow-y: auto; -webkit-overflow-scrolling: touch - 监听弹层根节点的
touchmove,仅当!e.target.closest('.modal-content')时才e.preventDefault() - 多层弹窗(比如抽屉里再开 Modal)需维护计数器,只有最外层关闭才恢复滚动,否则底层提前解锁
- 真正麻烦的不是锁,而是解锁时
scrollY是否精准——快速开关或中途手动滚动后,值容易错位,务必双取值还原
最终效果是否可靠,不取决于你写了多少 CSS,而取决于三件事是否同时到位:position: fixed 钉住视口、touchmove 精准拦截、scrollY 精确还原。少一个,iOS 上的滑动就会找上门。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










