100vh no Safari do iPhone: a barra de endereço, dvh, svh e lvh
Por que o 100vh passa da tela no iPhone, as três unidades que substituem ele, qual usar em cada layout e o que a barra do iOS 26 mudou.
Atualizado em ·5 min de leitura
SafariiPhone 17 Pro · 402 × 874
6294viewport 718
Resposta curta: no Safari do iPhone, 100vh é a altura da tela com a barra do Safari recolhida. Quando a página abre, a barra está aparecendo, então um bloco de 100vh fica maior que a parte visível e o fim dele vai parar atrás da barra. Use 100svh no que precisa caber na primeira tela, 100dvh só em telas de app que devem acompanhar a barra, e deixe o 100vh como linha de reserva.
.hero {
min-height: 100vh; /* reserva para navegadores de antes de 2022 */
min-height: 100svh; /* cabe com a barra aparecendo */
}
Isso não é um bug que a Apple vai corrigir. O relato no WebKit está aberto desde 2015, e o comportamento hoje está escrito na especificação do CSS.
Por que o 100vh fica maior que a tela
O navegador do celular tem três alturas para a mesma tela:
Viewport pequeno (svh): a barra do navegador aparece inteira. É o que você vê quando a página abre.
Viewport grande (lvh): a barra recolheu depois que você rolou para baixo.
Viewport dinâmico (dvh): o que for verdade agora, mudando enquanto a barra se mexe.
A especificação CSS Values 4 diz que o vh comum vale o viewport grande, por compatibilidade. O Safari faz assim, e o Chrome do Android também. Então 100vh é igual a 100lvh, mais alto que a tela visível na abertura.
Num iPhone 16 Pro ou 17 Pro com iOS 26, no layout de abas Compacto (o padrão), o window.innerHeight mede 718 px com a barra aberta e 754 px com ela recolhida. Um hero de 100vh fica uns 36 px maior que o visível, o bastante para esconder a seta de rolar ou o botão principal do rodapé.
Qual unidade usar
Layout
Use
Por quê
Hero, primeira tela, splash
min-height: 100svh
Sempre cabe com a barra aparecendo e não muda de tamanho na rolagem
Imagem de fundo de tela cheia
100lvh
Cobre a tela mesmo com a barra recolhida, sem faixa vazia
Tela de app, chat, mapa com campo fixo embaixo
height: 100dvh
Acompanha a barra, a última linha continua visível
Modal ou camada de tela cheia
position: fixed; inset: 0
Ocupa a área visível sem unidade nenhuma
Página comprida com rolagem
Evite dvh
A altura muda enquanto a pessoa rola e a página treme
svh, lvh e dvh funcionam no Safari 15.4 em diante, Chrome e Edge 108+, Firefox 101+ e Samsung Internet 21+, cerca de 96% dos usuários. Escrever o 100vh antes e a unidade nova depois já serve de reserva; o @supports é opcional.
.app {
height: 100vh;
height: 100dvh;
display: grid;
grid-template-rows: auto 1fr auto; /* cabeçalho, área que rola, campo de mensagem */
}
.app main { overflow-y: auto; }
Pode tirar os truques antigos
height: -webkit-fill-available só funcionava no WebKit, quebra no Chrome e não é necessário desde o Safari 15.4, de março de 2022.
A variável --vh por JavaScript (innerHeight * 0.01 gravado numa variável a cada resize) era a saída para o Safari antes do 15.4. Hoje é mais lenta e menos precisa que svh e dvh. Só mantenha se ainda atende iOS 15.3 ou anterior.
O que mudou no iOS 26
O iOS 26 trouxe o Liquid Glass para o Safari: no layout Compacto, a barra de abas flutua embaixo e a página rola por baixo dela.
O conteúdo pode ficar sob a barra. Com viewport-fit=cover na meta viewport, a página se estende por baixo da barra de vidro. Elementos fixos no rodapé precisam de padding-bottom: env(safe-area-inset-bottom), senão a barra cobre.
O theme-color não pinta mais a barra. O Safari 26 tira a cor da própria página: o fundo do html e do body e os elementos fixos ou sticky perto das bordas de cima e de baixo. Defina html { background: … } e esconda camadas fechadas com display: none (uma camada com opacity: 0 continua pintando a barra).
Os bugs dos primeiros 26.x foram corrigidos. O Safari 26.1 corrigiu uma faixa vazia embaixo em layouts com contêiner fixo do tamanho da tela; o 26.2 fez o fundo do <dialog> em tela cheia passar por baixo da barra de endereço e parou de sumir com elementos fixos na borda durante a rolagem elástica. Se você colocou um remendo em setembro de 2025, teste de novo.
Uma barra fixa no rodapé que respeita a barra do Safari e o indicador de início:
html { background: #fff; }
.barra-de-abas {
position: fixed;
inset-inline: 0;
bottom: 0;
padding-bottom: max(env(safe-area-inset-bottom), 12px);
background: #fff; /* sólido: é também o que o Safari 26 usa para pintar a barra */
}
Muita gente espera que o 100dvh diminua quando o teclado abre. Não diminui, nem no iOS nem no Chrome do Android desde a versão 108: o teclado só muda o viewport visual, e as unidades continuam iguais. Para manter o campo de mensagem acima do teclado, ouça o visualViewport:
No Android dá para voltar ao comportamento antigo com interactive-widget=resizes-content na meta viewport. O Safari ignora essa opção.
Como testar
iPhone de verdade: o único jeito de ver a barra recolher, o teclado e a rolagem elástica. Abra a página, confira a primeira tela, role um pouco, confira de novo e toque num campo.
Modo celular do DevTools: mostra um viewport fixo, sem barra, então 100vh, svh e dvh dão o mesmo valor. Ele não mostra esse problema.
Breakpane: desenha a barra do Safari do iOS 26 (e a do Chrome no Android) em volta de um viewport do tamanho que o Safari informa com a barra aberta, no Windows ou no Mac. Serve para conferir o resultado: a primeira tela cabe, nada fica atrás da barra nem do indicador de início. A barra não recolhe e o motor é o Chromium, então lá vh, svh e dvh são iguais e o estouro do 100vh em si não aparece. A rolagem e o teclado ficam para o iPhone de verdade.