ios中仅用overflow:hidden无效,需结合position:fixed锁定body、保存还原滚动位置,并对遮罩内可滚动区域条件拦截touchmove或使用overscroll-behavior降级处理。

只靠 overflow: hidden 在 iOS 上基本无效
给 body 加 overflow: hidden 看似合理,但在 iOS Safari(尤其 12–15)和部分安卓 WebView 中,它仅隐藏滚动条,不拦截 touchmove 的默认滚动行为。手指在遮罩层上滑动,底层页面照样惯性滚动——这不是你 CSS 写错了,是 WebKit 的机制限制。
常见错误现象:开发者工具里看到 body 的 computed overflow 确实是 hidden,但真机一滑,背景页还是动了;或者加了内联 style="overflow: hidden",却被 Ant Design、uView 等 UI 框架的挂载逻辑覆盖。
实操建议:
- 优先用 class 控制,定义
.no-scroll { overflow: hidden !important; },再用document.body.classList.add('no-scroll') - 检查 CSS 加载顺序,确保该 class 规则在所有其他影响
body的样式之后生效 - 打开遮罩后,在开发者工具中选中
,确认 computedoverflow最终值未被标记为overridden
必须配合 position: fixed 锁定 body 位置
position: fixed 不是为了“固定弹窗”,而是让 body 脱离文档流,物理上失去被拖拽滚动的能力。但直接设会跳顶,所以得同步保存并还原滚动偏移。
实操建议:
- 显示遮罩前,记录:
const scrollY = window.pageYOffset || document.documentElement.scrollTop - 然后设置:
document.body.style.position = 'fixed'; document.body.style.top = `-${scrollY}px` - 关闭遮罩时,先清除样式:
document.body.style.position = ''; document.body.style.top = '',再执行window.scrollTo(0, scrollY) - 不要只读写
document.body.scrollTop,iOS 中它常为 0,必须优先用window.pageYOffset
遮罩内可滚动区域必须显式放行 touchmove
如果弹窗内容超长(比如带选项列表的规格选择器),你不能全局阻止 touchmove,否则 textarea、input、内部列表全失灵。
实操建议:
- 给可滚动容器加 class,如
.modal-content,并设max-height: 80vh; overflow-y: auto; -webkit-overflow-scrolling: touch - 在遮罩根元素上监听
touchmove:if (!e.target.closest('.modal-content')) e.preventDefault() - 绝对不要对
document或body绑定touchmove并无差别preventDefault,这会干掉所有原生滚动控件
overscroll-behavior 是现代方案,但需 JS 补漏
overscroll-behavior: contain 是目前最干净的解法,它明确告诉浏览器:“这个容器滚到边了,别把滚动传给父级”。但它不支持 iOS 15 以下和旧版安卓 WebView。
实操建议:
- 对遮罩内可滚动区设:
.modal-content { overscroll-behavior: contain; overflow-y: auto; } - 对
body设:body { overscroll-behavior: none; } - 兼容老系统时,仍需在遮罩显示时绑定
document.addEventListener('touchmove', e => e.preventDefault(), { passive: false }),并确保{ passive: false }—— 否则preventDefault在 Safari/Chrome 中会被忽略
touchmove 的条件拦截、overscroll-behavior 的降级 fallback,这三者缺一不可。漏掉任意一个,都可能在某台 iOS 设备或某个 WebView 版本里突然失效。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











