📓 Scroll anchoring quebrando sua UI? Um bug sutil que bagunçou meu modal e me forçou a investigar propriedades menos conhecidas do CSS.
🌊 IA com memória simbólica, LLMs no celular e o Sora disponível via Bing.
📦 Tesouros: modelo open-source de áudio editável, jogo de CSS com Flexbox e geradores visuais pra glassmorphism & neumorphism.
Sabe aquele tipo de bug que aparece mesmo quando você faz tudo certo?
Essa semana, caí de novo nessa armadilha e, sinceramente, ela tem muito a dizer sobre o lado menos glamouroso do front-end avançado.
Eu estava implementando um modal com steps. A ideia era simples: cabeçalho fixo, rodapé fixo e conteúdo do meio scrollando. A receita estava na mão: display: flex, flexDirection: column, minHeight: 0, overflowY: auto… Tudo como manda o figurino.
Funcionou. Ou melhor: quase.
Numa das abas do modal, renderizei uma tabela com checkboxes. E foi aí que o Chrome e o Edge decidiram me lembrar quem manda: ao marcar uma linha, o conteúdo pulava pra cima do nada, criando um vácuo visual na tela.
A solução veio com dois ingredientes obscuros:
overflow-anchor: none;
contain: layout;
Essas propriedades foram como remédios pra um sintoma que eu nem sabia nomear: o scroll anchoring automático tentando “ajudar”, mas causando caos.
O bug estava ligado ao scroll anchoring, uma feature nativa dos navegadores modernos (implementada principalmente em Chromium) que tenta preservar a posição de rolagem automaticamente quando o DOM muda. A intenção é boa, por exemplo, manter o ponto de leitura visível enquanto elementos carregam acima, mas em alguns contextos dinâmicos, ela faz justamente o oposto do que deveria.
No meu caso, marcar uma checkbox dentro da tabela fazia o DOM mudar de forma sutil. Isso era suficiente pro Chrome “achar” que precisava reajustar a âncora de scroll, e o conteúdo acabava pulando, gerando um espaço em branco nada sutil.
Foi aí que entrou o overflow-anchor: none. Essa propriedade diz pro navegador: “não tente manter o scroll ancorado aqui”. Ela é essencial em contextos de UI interativa onde mudanças visuais não devem impactar a posição da rolagem.
Junto a isso, o contain: layout atuou como reforço: ele informa ao navegador que aquele container tem um layout isolado, ou seja, mudanças dentro dele não devem interferir no layout fora dele (nem vice-versa). Isso ajuda a limitar reflows, melhora performance, e neste caso específico, impediu efeitos colaterais inesperados de render.