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
iPhone 17 Pro no Safari com as cotas das barras de cima e de baixo

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:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
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 */
}

Mais sobre os insets em Safe area não funciona.

O teclado não muda o dvh

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:

const vv = window.visualViewport;
const atualizar = () => {
  const teclado = Math.max(0, innerHeight - vv.height - vv.offsetTop);
  document.documentElement.style.setProperty('--teclado', teclado + 'px');
};
vv.addEventListener('resize', atualizar);
vv.addEventListener('scroll', atualizar);
.campo-de-mensagem { bottom: var(--teclado, 0px); }

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.

Outros guias

  1. PWAiPhone 17 Pro · 402 × 874
    Tela de início do iPhone 17 Pro com o ícone de um PWA instalado
    Como testar um PWA no iPhone e no Android: modo standalone, ícone, splash e offline
  2. Safe areaiPhone 17 Pro · 402 × 874
    iPhone 17 Pro com um app em tela cheia e as cotas das áreas seguras
    Safe area não funciona? Por que env(safe-area-inset-bottom) dá 0
  3. WindowsiPhone Air · 420 × 912
    iPhone Air com um app no modo escuro e a cota de largura
    Simulador de iPhone para PC: como testar o seu site no iPhone usando Windows