Cuando se abre un elemento <dialog> como un modal con showModal(), el navegador lo promueve a la capa superior y marca el resto del documento como inerte. Si bien esto bloquea los clics del puntero y el enfoque del teclado en la página subyacente, no impide el desplazamiento:
- Si te desplazas mientras el puntero o el gesto táctil están sobre el
::backdrop, se desplazará la página que está debajo. - El desplazamiento dentro de
<dialog>se encadena a la página subyacente una vez que el diálogo alcanza su límite de desplazamiento, o de inmediato si el contenido del diálogo no se desborda.
Según la especificación del comportamiento de sobredesplazamiento de CSS, overscroll-behavior se aplica a todos los elementos de contenedor de desplazamiento, incluidos los contenedores de desplazamiento no desplazables (elementos con overflow: hidden o overflow: auto cuyo contenido no se desborda actualmente). Si combinas overscroll-behavior: contain en <dialog> con overflow: hidden y overscroll-behavior: contain en dialog::backdrop, puedes evitar que se desplace la página subyacente con CSS puro.
Implementación
1. Contener el encadenamiento de desplazamiento en el <dialog>
La hoja de estilo del usuario-agente establece overflow: auto en <dialog>, lo que lo convierte en un contenedor de desplazamiento de forma predeterminada. Aplica overscroll-behavior: contain (o none) a dialog:modal (o dialog).
2. Convierte ::backdrop en un contenedor de desplazamiento y limita su desplazamiento
De forma predeterminada, dialog::backdrop tiene overflow: visible, lo que significa que no es un contenedor de desplazamiento y que ignora overscroll-behavior. Debes establecer overflow: hidden en dialog::backdrop para que sea un contenedor de desplazamiento no desplazable y vincularlo con overscroll-behavior: contain para que los gestos de desplazamiento que se realicen sobre el fondo se capturen y no lleguen al documento que se encuentra debajo.
Código de ejemplo
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;
}
Prácticas recomendadas y restricciones
- OBLIGATORIO: Establece
overscroll-behavior: containen el elemento<dialog>(con el selectordialog:modal) y endialog::backdrop. Sin esta declaración, los gestos de desplazamiento sobre el fondo o dentro del diálogo seguirán encadenándose a la página. - OBLIGATORIO: Establece
overflow: hidden(ooverflow: auto) endialog::backdroppara que se convierta en un contenedor de desplazamiento. Sin esta declaración,::backdropse establece de forma predeterminada enoverflow: visibleyoverscroll-behaviorno tendrá ningún efecto. - NO uses
overflow: clipnioverflow: visibleendialog::backdropnidialog. Ninguno de los valores establece un contenedor de desplazamiento, por lo que no se aplicaráoverscroll-behavior. - NO apliques
overflow: hiddenniposition: fixeda<html>ni<body>para bloquear el desplazamiento en segundo plano cuando se abre un diálogo. La mutación del desbordamiento de la raíz quita la barra de desplazamiento de la página (lo que provoca un cambio de diseño horizontal), puede restablecer o saltar la posición de desplazamiento de la página y puede romper los elementosposition: stickyde la página subyacente.
Estrategias de resguardo
Si bien la propiedad de CSS overscroll-behavior es compatible con todos los navegadores principales para los contenedores de desplazamiento que tienen contenido desbordado, respetar overscroll-behavior en los contenedores de desplazamiento no desplazables es una especificación más reciente que no se puede detectar.
NO intentes detectar la compatibilidad con contenedores no desplazables con @supports (overscroll-behavior: contain) o CSS.supports('overscroll-behavior', 'contain'). Todos los navegadores actualizados admiten la sintaxis de la propiedad overscroll-behavior: contain y devuelven true, incluso si solo la aplican cuando el contenido se desborda.
En su lugar, trata la contención de desplazamiento en contenedores de desplazamiento no desplazables como una mejora progresiva:
- En los navegadores que admiten
overscroll-behavioren contenedores de desplazamiento no desplazables, se evita por completo el desplazamiento de la página en segundo plano tanto sobredialog::backdropcomo dentro de<dialog>(independientemente de si su contenido se desborda o no). - En los navegadores que aún no admiten
overscroll-behavioren contenedores de desplazamiento no desplazables,overscroll-behavior: containendialogsigue impidiendo el encadenamiento de desplazamiento cada vez que el contenido del diálogo se desborda y se puede desplazar. Mientras tanto,showModal()sigue atrapando el enfoque del teclado y marca el documento en segundo plano comoinert. - Se recomienda confiar en la mejora progresiva en lugar de las soluciones heredadas que aplican
overflow: hiddenoposition: fixeda<html>o<body>, ya que no quita la barra de desplazamiento raíz, no provoca cambios de diseño horizontales, no salta la posición de desplazamiento de la página ni rompe los elementosposition: stickyen la página subyacente.