模态框打开后页面仍可滚动,需用 body.modal-open { overflow: hidden !important; } 精准禁用;内容不滚动需确保父容器有高度约束和 overflow-y: auto;防滚动穿透应使用 overscroll-behavior-y: contain 于实际可滚动区域。

模态框打开后页面还能滚?先锁住 body
这不是模态框没写滚动,而是 body 没真正禁用滚动。Bootstrap 会在打开时加 modal-open 类,但你的 CSS 可能覆盖了它默认的 overflow: hidden。直接写 body { overflow: hidden } 更危险——关闭模态框后滚动不会自动恢复。
正确做法是只兜底:body.modal-open { overflow: hidden !important; }。确保这条规则在 Bootstrap CSS 加载之后生效,且不要加其他影响 body 的无条件 overflow 规则。
模态框内容不滚动?检查高度约束和 overflow-y
常见错觉是“我写了 overflow-y: auto,但它就是不滚”,大概率是因为父容器没定高,或者子内容根本没溢出。比如 .modal-body 是 flex 子项,但它的父级 .modal-content 没设 max-height 或 height,那 overflow-y 就完全无效。
-
.modal-dialog-scrollable必须配合显式高度约束(如max-height: 80vh)才起作用 - 避免给
.modal-content设min-height或height: 100%—— 它会撑开整个模态框,导致滚动区失效 - 移动端建议用
max-height: calc(100vh - 120px)预留顶部导航栏空间
父子滚动穿透:别碰 touchmove,用 overscroll-behavior
用户在模态框里滑到底,继续拖会把页面也带上滚——这不是 JS 事件冒泡,是浏览器 scroll chaining 行为。别在 touchmove 里对 document 调 preventDefault(),这会锁死所有内部滚动。
只对真正可滚动的区域设置:.modal-body { overscroll-behavior-y: contain; }。注意三点:
- 必须作用于实际设置了
overflow-y: auto且内容超高的元素(比如.modal-body),不是外层.modal或.modal-dialog - 该元素必须有明确高度(
max-height)、overflow-y: auto、内容真实溢出,三者缺一不可 - 优先用
contain,不是none;none会干掉 iOS 下拉刷新提示,用户感知“卡死”
iOS 15 及以下不支持 overscroll-behavior?降级要精准
CSS.supports('overscroll-behavior', 'contain') 返回 false 时才需 JS 补位。但别全局拦截 touchmove,否则横向轮播、内部 iframe 滚动全挂了。
只在非目标滚动区做限制:
- 监听
touchmove,用event.target.closest('.modal-body')检查是否在可滚动区域里 - 如果返回
null(即不在可滚动区),再调event.preventDefault() - 同时确保
.modal-body本身设置了touch-action: pan-y,避免被系统手势吞掉
最易被忽略的是:overscroll-behavior 不生效时,很多人第一反应是加 position: relative 或改 z-index,其实它跟层叠上下文无关,只看是否满足“可滚动+有高度+内容溢出”这三个硬条件。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











