滚动事件不冒泡,所谓“背景滚动”实为 Safari 的滚动上下文切换穿透;应通过 overscroll-behavior: contain + body overflow 控制,并确保 DOM 结构正确。

局部滚动容器的事件冒泡根本不存在
滚动事件(scroll)在规范中明确不冒泡——它只在触发滚动的元素上触发,或在 Document 上触发(此时也不向上冒泡到 window)。所以你无法、也不该试图用 event.stopPropagation() 去“阻止滚动冒泡”。常见误解是:弹窗打开后滑动内部列表,背景页跟着动 → 这不是冒泡,是 Safari 的 viewport 滚动穿透,和事件流无关。
为什么给内部容器加 touchmove.preventDefault() 会失效或误伤
直接在弹窗遮罩层监听 touchmove 并调用 e.preventDefault(),看似能锁住页面,实则有两个硬伤:
- 在 iOS Safari 中,若未显式传入
{ passive: false },浏览器会忽略preventDefault(),滚动照常穿透 - 它会一并封死弹窗内所有可滚动子区域(比如
.modal-scrollable),用户点进去反而滑不动
正确做法是:只对非滚动子区域拦截,对已设 overflow-y: auto 且有高度约束的容器放行。例如:
mask.addEventListener('touchmove', (e) => {
if (!e.target.closest('.modal-scrollable')) {
e.preventDefault();
}
});
真正要防的是滚动上下文切换导致的穿透
iOS Safari 在内部滚动触顶/触底后,会自动把后续拖拽交还给 viewport,造成“背景滚动”假象。这不是事件传播问题,而是滚动源切换。解决必须分两层:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
- CSS 层:给真正滚动的容器(如
.modal-content)加overscroll-behavior: contain,且确保它有max-height和overflow-y: auto - JS 层:iOS 真机兜底,弹窗打开时执行
document.body.style.overflow = 'hidden',同时记录savedScrollY = window.scrollY;关闭时恢复window.scrollTo(0, savedScrollY)
注意:overscroll-behavior 写在 position: fixed 的弹窗外壳上无效——它必须落在那个实际发生滚动的、带尺寸限制的子容器上。
嵌套滚动里点击穿透和滚动穿透是两回事
点击类交互(如按钮、链接)才走 DOM 事件流,才可能冒泡;滚动不是。如果你发现点弹窗里的按钮,外层卡片也响应了,那是典型的 click 冒泡没处理,该用 e.stopPropagation();但如果你发现滑动弹窗内容时背景页在动,那跟事件冒泡完全无关,是滚动上下文管理缺失。
最容易被忽略的一点:DOM 结构异常(比如漏闭合的 <div>)会让浏览器自动纠错,导致你写的 .modal-scrollable 实际被包裹进一个意外父容器里,CSS 高度和 overscroll-behavior 全部失效——先用 DevTools 的 Show DOM properties 查 depth,再确认结构是否被悄悄重写。


















