Cómo evitar que una página se desplace mientras un diálogo está abierto
Abrir un diálogo modal debería centrar la atención del usuario en ese diálogo, no permitirle desplazarse por la página detrás de él. Sin embargo, prevenir el desplazamiento del fondo sigue siendo sorprendentemente difícil, especialmente cuando necesitas un comportamiento confiable de bloqueo de desplazamiento en iOS Safari.
El elemento <dialog> con showModal() maneja el bloqueo de interacción automáticamente. El navegador marca todo lo que está fuera del diálogo como inert, previniendo clics y navegación por teclado. ¿Pero la prevención del desplazamiento? Ese es un problema separado que la plataforma no resuelve completamente.
Este artículo cubre los principales enfoques para implementaciones de diálogos modales con bloqueo de desplazamiento, sus compromisos, y por qué ninguna solución única funciona perfectamente en todas partes.
Puntos clave
- El método
showModal()bloquea la interacción pero no previene el desplazamiento del fondo - CSS
overflow: hiddenfunciona en escritorio pero falla en iOS Safari - La técnica del body fijo con restauración de posición de desplazamiento proporciona la solución multiplataforma más confiable
- Usa
overscroll-behavior: containjunto con otros métodos para prevenir el encadenamiento de desplazamiento - Mantén siempre tu diálogo desplazable con
max-heightyoverflow-y: autopara accesibilidad
Qué hace y qué no hace showModal()
Cuando llamas a dialog.showModal(), el navegador:
- Muestra el diálogo en la capa superior
- Crea un pseudo-elemento
::backdrop - Hace que el contenido de fondo sea inerte (bloquea la interacción con puntero y teclado)
- Atrapa el foco dentro del diálogo
Lo que no hace: prevenir de manera confiable el desplazamiento del fondo en todos los navegadores y dispositivos. En algunas plataformas, especialmente móviles, los usuarios aún pueden desplazar la página usando gestos táctiles o ruedas de desplazamiento.
El enfoque CSS simple: overflow: hidden
La solución más común usa el selector :has() para detectar un diálogo abierto:
body:has(dialog[open]) {
overflow: hidden;
}
Esto funciona en la mayoría de los navegadores de escritorio. La página se vuelve no desplazable mientras el diálogo está abierto.
El problema: Este enfoque no es confiable en iOS Safari. El desplazamiento táctil a menudo evita overflow: hidden en el body, permitiendo a los usuarios desplazar el fondo de todos modos. Si tu audiencia incluye usuarios de Safari móvil, necesitarás algo más robusto.
La técnica del body fijo para confiabilidad multiplataforma
La solución multiplataforma más confiable, incluyendo el bloqueo de desplazamiento en iOS Safari, usa JavaScript para fijar el body en su lugar:
let scrollPosition = 0;
function lockScroll() {
scrollPosition = window.scrollY;
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollPosition}px`;
document.body.style.width = '100%';
}
function unlockScroll() {
document.body.style.position = '';
document.body.style.top = '';
document.body.style.width = '';
window.scrollTo(0, scrollPosition);
}
Llama a lockScroll() al abrir el diálogo y unlockScroll() al cerrarlo.
Esta técnica almacena la posición de desplazamiento, fija el body para que no pueda desplazarse, y luego restaura todo al cerrar. Maneja el desplazamiento táctil en iOS porque el body literalmente no puede moverse.
Compromiso: Puedes ver un cambio de diseño si la barra de desplazamiento desaparece. Compensa agregando padding-right igual al ancho de la barra de desplazamiento al bloquear.
CSS overscroll-behavior para encadenamiento de desplazamiento
La propiedad overscroll-behavior previene el encadenamiento de desplazamiento, cuando desplazarse dentro de un elemento causa que un elemento padre se desplace después de alcanzar el límite.
dialog {
overscroll-behavior: contain;
}
dialog::backdrop {
overscroll-behavior: contain;
}
Las versiones recientes de Chromium (finales de 2025+) mejoraron este comportamiento, haciéndolo funcionar incluso en contenedores no desplazables. Esto ayuda con el bloqueo de desplazamiento de diálogos HTML en Chrome, pero otros navegadores aún no se han puesto al día completamente.
Importante: Las soluciones modales con CSS overscroll-behavior previenen el encadenamiento de desplazamiento, no el desplazamiento en sí. Si el usuario se desplaza directamente sobre el backdrop o el body, overscroll-behavior no lo detendrá. Usa esto junto con otras técnicas, no como reemplazo.
Discover how at OpenReplay.com.
Peculiaridades de iOS Safari que debes conocer
iOS Safari presenta desafíos únicos para prevenir el desplazamiento del fondo en implementaciones modales:
overflow: hiddenen body no bloquea de manera confiable el desplazamiento táctil- El efecto de rebote elástico puede provocar movimiento del fondo
- La aparición del teclado virtual puede causar comportamiento de desplazamiento inesperado
La técnica del body fijo sigue siendo la solución más confiable. Algunos desarrolladores también agregan touch-action: none al elemento backdrop (no al diálogo mismo), aunque esto puede interferir con el desplazamiento dentro del diálogo si se aplica de manera demasiado amplia.
Mantén tu diálogo desplazable
Un detalle crítico: si el contenido de tu diálogo excede la altura del viewport, el diálogo mismo debe desplazarse. Establece max-height y overflow-y: auto apropiados en el diálogo:
dialog {
max-height: 90vh;
overflow-y: auto;
}
Bloquear todo el desplazamiento crea problemas de accesibilidad. Los usuarios necesitan acceder a todo el contenido del diálogo.
Una nota sobre la API Popover
La API Popover existe para superposiciones ligeras pero no es un reemplazo directo para diálogos modales. Los popovers no bloquean la interacción del fondo de la misma manera, y el comportamiento de bloqueo de desplazamiento difiere. Para experiencias modales verdaderas que requieren bloqueo de desplazamiento, mantente con <dialog> y showModal().
Eligiendo tu enfoque
Para aplicaciones solo de escritorio, el enfoque CSS :has() con overflow: hidden a menudo es suficiente. Para confiabilidad multiplataforma, especialmente iOS Safari, usa la técnica del body fijo con restauración de posición de desplazamiento. Agrega overscroll-behavior: contain encima para prevenir el encadenamiento de desplazamiento en navegadores compatibles.
Conclusión
Ninguna solución funciona perfectamente en todas partes. La técnica del body fijo ofrece el bloqueo de desplazamiento multiplataforma más confiable, particularmente para iOS Safari. Combínala con overscroll-behavior: contain para protección adicional contra el encadenamiento de desplazamiento en navegadores Chromium. Prueba en dispositivos reales, particularmente iOS Safari, y acepta que algunos casos extremos pueden requerir compromisos.
Preguntas frecuentes
iOS Safari maneja el desplazamiento táctil de manera diferente que los navegadores de escritorio. El sistema de eventos táctiles del navegador puede evitar overflow hidden en el elemento body, permitiendo el desplazamiento del fondo incluso cuando la propiedad está establecida. La técnica del body fijo funciona porque posiciona físicamente el body fuera de la pantalla, haciendo el desplazamiento imposible en lugar de simplemente ocultarlo.
Sí, puede hacerlo. Cuando la barra de desplazamiento desaparece, el contenido puede desplazarse para llenar ese espacio. Para prevenir esto, calcula el ancho de la barra de desplazamiento y agrega padding-right equivalente al body al bloquear el desplazamiento. Elimina el padding al desbloquear. Esto mantiene un diseño consistente durante toda la interacción modal.
La API Popover sirve para un propósito diferente. Crea superposiciones ligeras sin bloquear la interacción del fondo ni proporcionar las mismas capacidades de bloqueo de desplazamiento. Para experiencias modales verdaderas donde los usuarios deben interactuar con el diálogo antes de continuar, usa el elemento dialog con showModal para un adecuado atrapamiento de foco y comportamiento inerte.
Establece overscroll-behavior contain en el diálogo para prevenir el encadenamiento de desplazamiento hacia el fondo. Asegúrate de que tu diálogo tenga max-height y overflow-y auto para que el contenido interno se desplace correctamente. Evita aplicar touch-action none a todo el diálogo, ya que esto bloquea el desplazamiento legítimo dentro del área de contenido modal.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.