# O macete para unidades de viewport em mobile

> Descubra o macete para unidades viewport (vh/vw) em mobile. Solução definitiva para problemas com barras de navegação em iOS e Android. Funciona!

URL: https://dpw.dev/css/o-macete-para-unidades-de-viewport-em-mobile/  
Publicado em: 2019-12-09  
Categoria: css  
Tags: layout, web-design-responsivo  
Autor: Tárcio Zemel

Unidades de viewport podem ser controversas, e parte disso é devido à maneira como os navegadores móveis tornaram as coisas mais complicadas ao terem suas próprias opiniões sobre como implementá-las.

Caso em questão: a barra de rolagem deve ser levada em consideração para a unidade `vw`? E quanto à navegação de um site ou aos controles de página, eles devem ser considerados no cálculo? Depois, existem atributos físicos dos próprios dispositivos que não podem ser ignorados -- olá, notch!

Recentemente, publicamos o artigo [Algumas coisas que você deve saber ao trabalhar com unidades de viewport](/css/algumas-coisas-que-voce-deve-saber-ao-trabalhar-com-unidades-de-viewport/), em que abordávamos um pouco sobre isso, mas o que você vai aprender a seguir, realmente vai um passo além.

## Um pouco de contexto

A especificação é bastante vaga sobre como as unidades de viewport devem ser calculadas. Em dispositivos móveis, geralmente nos preocupamos com a altura vertical; portanto, vejamos especificamente sobre **viewport height** (`vh`):

> **unidade vh**  
> Igual a 1% da altura do containing block inicial.

Então, sim, não há orientações claras quando se trata de lidar com diferenciações específicas de dispositivos e navegadores.

`vh` foi inicialmente calculado pela viewport atual do seu navegador. Se você abriu o navegador e começou a carregar um site, `1vh` era igual a 1% da altura da tela, menos a interface do navegador.

**Mas**... Se você começar a rolar a tela, é uma história diferente! Depois que você passa por uma parte da interface do navegador, como a barra de endereço, o valor `vh` será atualizado e o resultado será um salto estranho (awkward jump) no conteúdo.

O Safari para iOS foi um dos primeiros navegadores móveis a atualizar sua implementação, escolhendo definir um valor fixo para `vh` com base na altura máxima da tela. Ao fazer isso, o usuário não experimentaria saltos na página depois que a barra de endereços ficasse fora de vista. O navegador móvel do Chrome seguiu o exemplo.

Embora o uso de um valor fixo seja bom, isso também significa que você não pode ter um elemento de altura total se a barra de endereço estiver em exibição. A parte inferior do elemento será cortada.

<figure>

![Comparativo de telas mobile, uma mostrando o erro que acontece e a outra está correta devido à implementação do macete para unidades de viewport em mobile.](/images/blog/o-macete-para-unidades-de-viewport-em-mobile/o-macete-para-unidades-de-viewport-em-mobile-sad-happy.webp)

<figcaption>

Um elemento é cortado na parte inferior quando a barra de endereço está à vista (esquerda), mas o resultado desejado é ter a coisa completa (direita).

</figcaption>

</figure>

## CSS Custom Properties: o truque para corrigir o dimensionamento

**CSS Custom Properties** (mais conhecidas como **[Variáveis CSS](/css/variaveis-css-guia-pratico/)**) e algumas linhas de JavaScript podem ser a maneira perfeita de obter o dimensionamento consistente e correto que eu precisava.

Em JavaScript, é possível obter o valor da viewport atual usando a variável global `window.innerHeight`. Esse valor leva em conta a interface do navegador e é atualizado quando sua visibilidade muda. O truque é armazenar o valor da viewport em uma variável CSS e aplicá-lo ao elemento em vez da unidade `vh`.

Digamos que, neste exemplo, a variável CSS seja `--vh`. Isso significa que o código serial algo como:

```typescript
.my-element {
  height: 100vh; /* Fallback para não-suporte a Custom Properties */
  height: calc(var(--vh, 1vh) * 100);
}
```

Agora é pegar a altura interna da viewport no JavaScript:

```javascript
// Altura da viewport multiplicada por 1% para obter um valor para vh
let vh = window.innerHeight * 0.01;

// Configura o valor em --vh na raiz do documento
document.documentElement.style.setProperty('--vh', `${vh}px`);
```

O JS vai pegar a altura da viewport e a ajustar em 1/100 desse total para que se tenha um valor para atribuir como o valor da unidade de altura da viewport. Então, pedimos educadamente ao JS para criar a variável CSS (`--vh`) em `:root`.

Como resultado, agora é possível usar usar `--vh` como o valor de altura (tal como é possível com qualquer outra unidade de `vh`), multiplicá-lo por 100 e conseguir a altura total desejada.

[Exemplo no CodePen](https://codepen.io/anon/pen/vapjge)

## Opa, tem mais um detalhe!

Apesar de a solução já parecer concluída, aqueles com um olhar mais acurado para os detalhes podem ter percebido que o JavaScript é acionado, mas nunca atualiza o tamanho do elemento quando a altura da janela de visualização muda!

É possível atualizar o valor de `--vh` para ficar escutando o evento `resize` da janela. Isso é útil caso o usuário gire a tela do dispositivo ou a navegação saia da vista ao scrollar.

```javascript
// Escuta o evento resize
window.addEventListener('resize', () => {
  // Executa o mesmo script de antes
  let vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh', `${vh}px`);
});
```

Além disso, convém implementar um método de debounce para o evento de redimensionamento para evitar o acionamento de muitos eventos enquanto o usuário está redimensionando a janela do navegador. Veja [debouncing e throttling sendo explicados através de exemplos](https://css-tricks.com/debouncing-throttling-explained-examples/).

[Exemplo no CodePen](https://codepen.io/anon/pen/WKdJaB)

Agora sim o exemplo está funcionando corretamente.

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
