Como Impedir que uma Página Role Enquanto um Diálogo Está Aberto
Abrir um diálogo modal deve focar a atenção do usuário nesse diálogo—não permitir que ele role a página por trás. No entanto, prevenir a rolagem de fundo permanece surpreendentemente difícil, especialmente quando você precisa de um comportamento confiável de bloqueio de rolagem no iOS Safari.
O elemento <dialog> com showModal() lida automaticamente com o bloqueio de interação. O navegador marca tudo fora do diálogo como inert, impedindo cliques e navegação por teclado. Mas a prevenção de rolagem? Esse é um problema separado que a plataforma não resolve completamente.
Este artigo aborda as principais abordagens para implementações de diálogo modal com bloqueio de rolagem, suas compensações e por que nenhuma solução única funciona perfeitamente em todos os lugares.
Pontos-Chave
- O método
showModal()bloqueia a interação, mas não impede a rolagem de fundo - O CSS
overflow: hiddenfunciona em desktop, mas falha no iOS Safari - A técnica de body fixo com restauração da posição de rolagem fornece a solução cross-browser mais confiável
- Use
overscroll-behavior: containjunto com outros métodos para prevenir o encadeamento de rolagem - Sempre mantenha seu diálogo rolável com
max-heighteoverflow-y: autopara acessibilidade
O Que showModal() Faz e Não Faz
Quando você chama dialog.showModal(), o navegador:
- Exibe o diálogo na camada superior (top layer)
- Cria um pseudo-elemento
::backdrop - Torna o conteúdo de fundo inerte (bloqueia interação por ponteiro e teclado)
- Captura o foco dentro do diálogo
O que ele não faz: impedir de forma confiável a rolagem de fundo em todos os navegadores e dispositivos. Em algumas plataformas—principalmente mobile—os usuários ainda podem rolar a página usando gestos de toque ou rodas de rolagem.
A Abordagem CSS Simples: overflow: hidden
A solução mais comum usa o seletor :has() para detectar um diálogo aberto:
body:has(dialog[open]) {
overflow: hidden;
}
Isso funciona na maioria dos navegadores desktop. A página se torna não rolável enquanto o diálogo está aberto.
O problema: Esta abordagem não é confiável no iOS Safari. A rolagem por toque frequentemente ignora overflow: hidden no body, permitindo que os usuários rolem o fundo de qualquer forma. Se seu público inclui usuários do Safari mobile, você precisará de algo mais robusto.
A Técnica de Body Fixo para Confiabilidade Cross-Browser
A solução cross-browser mais confiável—incluindo bloqueio de rolagem no iOS Safari—usa JavaScript para fixar o body no 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);
}
Chame lockScroll() ao abrir o diálogo e unlockScroll() ao fechá-lo.
Esta técnica armazena a posição de rolagem, fixa o body para que não possa rolar, e então restaura tudo ao fechar. Ela lida com rolagem por toque no iOS porque o body literalmente não pode se mover.
Compensação: Você pode ver um deslocamento de layout se a barra de rolagem desaparecer. Compense adicionando padding-right igual à largura da barra de rolagem ao bloquear.
CSS overscroll-behavior para Encadeamento de Rolagem
A propriedade overscroll-behavior previne o encadeamento de rolagem—quando rolar dentro de um elemento faz com que um elemento pai role após atingir o limite.
dialog {
overscroll-behavior: contain;
}
dialog::backdrop {
overscroll-behavior: contain;
}
Versões recentes do Chromium (final de 2025+) melhoraram esse comportamento, fazendo-o funcionar mesmo em contêineres não roláveis. Isso ajuda com o bloqueio de rolagem de diálogo HTML no Chrome, mas outros navegadores ainda não alcançaram isso completamente.
Importante: Soluções modais com CSS overscroll-behavior previnem o encadeamento de rolagem, não a rolagem em si. Se o usuário rolar diretamente no backdrop ou body, overscroll-behavior não vai impedir. Use isso junto com outras técnicas, não como substituto.
Discover how at OpenReplay.com.
Peculiaridades do iOS Safari Que Você Deve Conhecer
O iOS Safari apresenta desafios únicos para prevenir rolagem de fundo em implementações modais:
overflow: hiddenno body não bloqueia de forma confiável a rolagem por toque- O efeito de overscroll elástico pode acionar movimento de fundo
- O aparecimento do teclado virtual pode causar comportamento de rolagem inesperado
A técnica de body fixo permanece a solução mais confiável. Alguns desenvolvedores também adicionam touch-action: none ao elemento backdrop (não ao diálogo em si), embora isso possa interferir com a rolagem dentro do diálogo se aplicado de forma muito ampla.
Mantenha Seu Diálogo Rolável
Um detalhe crítico: se o conteúdo do seu diálogo exceder a altura da viewport, o próprio diálogo deve rolar. Defina max-height e overflow-y: auto apropriados no diálogo:
dialog {
max-height: 90vh;
overflow-y: auto;
}
Bloquear toda a rolagem cria problemas de acessibilidade. Os usuários precisam acessar todo o conteúdo do diálogo.
Uma Nota sobre a Popover API
A Popover API existe para overlays leves, mas não é um substituto direto para diálogos modais. Popovers não bloqueiam a interação de fundo da mesma forma, e o comportamento de bloqueio de rolagem difere. Para experiências modais verdadeiras que requerem bloqueio de rolagem, fique com <dialog> e showModal().
Escolhendo Sua Abordagem
Para aplicações apenas desktop, a abordagem CSS :has() com overflow: hidden geralmente é suficiente. Para confiabilidade cross-browser—especialmente iOS Safari—use a técnica de body fixo com restauração da posição de rolagem. Adicione overscroll-behavior: contain por cima para prevenir encadeamento de rolagem em navegadores compatíveis.
Conclusão
Nenhuma solução funciona perfeitamente em todos os lugares. A técnica de body fixo oferece o bloqueio de rolagem cross-browser mais confiável, particularmente para iOS Safari. Combine-a com overscroll-behavior: contain para proteção adicional contra encadeamento de rolagem em navegadores Chromium. Teste em dispositivos reais, particularmente iOS Safari, e aceite que alguns casos extremos podem exigir compromisso.
Perguntas Frequentes
O iOS Safari lida com rolagem por toque de forma diferente dos navegadores desktop. O sistema de eventos de toque do navegador pode ignorar overflow hidden no elemento body, permitindo rolagem de fundo mesmo quando a propriedade está definida. A técnica de body fixo funciona porque posiciona fisicamente o body fora da tela, tornando a rolagem impossível em vez de apenas oculta.
Sim, pode causar. Quando a barra de rolagem desaparece, o conteúdo pode se deslocar para preencher esse espaço. Para prevenir isso, calcule a largura da barra de rolagem e adicione padding-right equivalente ao body ao bloquear a rolagem. Remova o padding ao desbloquear. Isso mantém o layout consistente durante toda a interação modal.
A Popover API serve a um propósito diferente. Ela cria overlays leves sem bloquear a interação de fundo ou fornecer as mesmas capacidades de bloqueio de rolagem. Para experiências modais verdadeiras onde os usuários devem interagir com o diálogo antes de continuar, use o elemento dialog com showModal para captura de foco adequada e comportamento inerte.
Defina overscroll-behavior contain no diálogo para prevenir encadeamento de rolagem para o fundo. Certifique-se de que seu diálogo tenha max-height e overflow-y auto para que o conteúdo interno role adequadamente. Evite aplicar touch-action none ao diálogo inteiro, pois isso bloqueia a rolagem legítima dentro da área de conteúdo 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.