当使用 showModal() 将 <dialog> 元素作为模态框打开时,浏览器会将其提升到顶层,并将文档的其余部分标记为惰性。虽然这会阻止指针点击和键盘焦点落在底层页面上,但不会阻止滚动:
- 当指针或轻触手势位于
::backdrop上时,滚动操作会滚动下方的页面。 - 在
<dialog>内滚动时,一旦对话框到达滚动边界,滚动操作就会链接到下层页面;如果对话框的内容没有溢出,则会立即链接到下层页面。
根据 CSS 滚动回弹行为规范,overscroll-behavior 适用于所有滚动容器元素,包括不可滚动的滚动容器(具有 overflow: hidden 或 overflow: auto 且其内容当前未溢出的元素)。通过将 <dialog> 上的 overscroll-behavior: contain 与 dialog::backdrop 上的 overflow: hidden 和 overscroll-behavior: contain 结合使用,您可以使用纯 CSS 阻止底层页面滚动。
实现
1. 在 <dialog> 上包含滚动链
用户代理样式表在 <dialog> 上设置 overflow: auto,使其默认成为滚动容器。将 overscroll-behavior: contain(或 none)应用于 dialog:modal(或 dialog)。
2. 将 ::backdrop 转换为滚动容器并包含其滚动
默认情况下,dialog::backdrop 具有 overflow: visible,这意味着它不是滚动容器,并且会忽略 overscroll-behavior。您必须在 dialog::backdrop 上设置 overflow: hidden,使其成为不可滚动的滚动容器,并将其与 overscroll-behavior: contain 配对,以便捕获在背景上执行的滚动动作,而不会到达其下方的文档。
示例代码
dialog:modal {
/* MANDATORY: Prevent scroll gestures inside the modal (even when its content
does not overflow) from chaining to the underlying page. */
overscroll-behavior: contain;
}
dialog::backdrop {
/* MANDATORY: ::backdrop defaults to overflow: visible (not a scroll container).
Set overflow: hidden so it becomes a non-scrollable scroll container that
honors overscroll-behavior. */
overflow: hidden;
overscroll-behavior: contain;
}
最佳实践和限制
- 强制性:在
<dialog>元素本身(使用dialog:modal选择器)和dialog::backdrop上设置overscroll-behavior: contain。如果没有此声明,在背景上或对话框内执行的滚动手势仍会链接到页面。 - 强制性:在
dialog::backdrop上设置overflow: hidden(或overflow: auto),使其成为滚动容器。如果没有此声明,::backdrop默认为overflow: visible,并且overscroll-behavior将不起作用。 - 请勿在
dialog::backdrop或dialog上使用overflow: clip或overflow: visible。这两个值都不会建立滚动容器,因此overscroll-behavior不会应用。 - 请勿在对话框打开时将
overflow: hidden或position: fixed应用于<html>或<body>来锁定背景滚动。更改根溢出属性会移除页面滚动条(导致水平布局偏移),可能会重置或跳过页面滚动位置,并可能会破坏底层页面上的position: sticky元素。
后备策略
虽然所有主流浏览器都支持在内容溢出的滚动容器上使用 overscroll-behavior CSS 属性,但在不可滚动的滚动容器上遵循 overscroll-behavior 是一项较新的规范,无法进行功能检测。
请勿尝试使用 @supports (overscroll-behavior: contain) 或 CSS.supports('overscroll-behavior', 'contain') 检测对不可滚动容器的支持。所有现代浏览器都支持 overscroll-behavior: contain 属性语法并返回 true,即使它们仅在内容溢出时才强制执行该属性。
相反,应将不可滚动容器上的滚动包含视为渐进增强:
- 在支持对不可滚动滚动容器使用
overscroll-behavior的浏览器中,系统会完全阻止在dialog::backdrop上方和<dialog>内部(无论其内容是否溢出)滚动背景页面。 - 在尚不支持对不可滚动滚动容器使用
overscroll-behavior的浏览器中,只要对话框自身的内容溢出且可滚动,对dialog使用overscroll-behavior: contain仍可防止滚动链。与此同时,showModal()仍会捕获键盘焦点,并将背景文档标记为inert。 - 建议您采用渐进增强,而不是采用将
overflow: hidden或position: fixed应用于<html>或<body>的旧版解决方法,因为渐进增强不会移除根滚动条、导致水平布局偏移、跳过页面滚动位置或破坏底层页面上的position: sticky元素。