Endereçamento da barra de endereços do iOS em layouts de 100vh

Isto não é um erro, é um recurso.

Quando implantei minha primeira conversão PSD com sua bela imagem de herói de 100vh e 100vw, fiquei horrorizada ao descobrir que a parte inferior do meu layout estava oculta quando visualizada no iPhone 6s iOS 10 Safari. Por quê? Eu pensei que fiz tudo certo! Eu adicionei acidentalmente margem ou preenchimento em algum lugar? O que eu estava ignorando?

Após uma inspeção mais detalhada, percebi rapidamente que, embora a imagem do meu herói fosse de fato 100vh, ela estava parcialmente coberta pelo endereço e pela barra de ferramentas do Safari, criando o temido "rolo de manobra". Tudo bem, pensei. Nada que uma pesquisa rápida no Google e Stack Overflow não consiga consertar. No entanto, aprendi que a solução não é tão direta.

Depois de fazer algumas pesquisas, percebi que era uma reclamação bastante comum, chamada de "bug de rolagem na janela de visualização do iOS". Em fevereiro de 2015, Nicolas Hoizy relatou o bug no Webkit Bugzilla quando descobriu que a parte inferior do seu jogo móvel de 100vh foi cortada pela barra de botões do navegador. Benjamin Poulain, engenheiro da Apple, respondeu a Hoizy. Ele afirmou - na verdadeira maneira de programador - que não era um bug, é um recurso.

Isso é completamente intencional. Demorou um pouco de trabalho de nossa parte para alcançar esse efeito. :)

O problema básico é este: a área visível muda dinamicamente à medida que você rola. Se atualizarmos a altura da janela de exibição CSS de acordo, precisamos atualizar o layout durante a rolagem. Não apenas isso parece uma merda, mas fazer isso a 60 FPS é praticamente impossível na maioria das páginas (60 FPS é a taxa de quadros da linha de base no iOS).

É difícil mostrar a parte "parece uma merda", mas imagine que enquanto você rola, o conteúdo se move e o que você deseja na tela muda continuamente.

A atualização dinâmica da altura não estava funcionando, tivemos algumas opções: soltar unidades de viewport no iOS, corresponder ao tamanho do documento como antes do iOS 8, usar o tamanho pequeno da visualização, usar o tamanho grande da visualização.

A partir dos dados que tínhamos, usar o tamanho de visualização maior foi o melhor compromisso. A maioria dos sites que usam unidades de visualização estava ótima na maior parte do tempo.

Eu, por exemplo, não sou engenheiro da Apple, por isso acredito nele quando ele diz que há boas razões por que eles criaram esse comportamento. Assim, o bug foi marcado como “RESOLVED WONTFIX”, e eu percebi que teria que me aprofundar mais se quisesse minha linda imagem de herói de 100vh.

Solução 1: consultas de mídia CSS

Este método, embora não seja totalmente elegante, é simples e fácil de implementar. Basta segmentar todos os dispositivos iOS com largura e altura específicas. Aqui está um código, cortesia de pburtchaell, em que ".foo" seria uma classe no seu elemento de altura total.

@media all e (largura do dispositivo: 768px) e (altura do dispositivo: 1024px) e (orientação: retrato) {
    .foo {
        altura: 1024px;
    }
}
                                            
/ * iPad com orientação paisagem. * /
@media all e (largura do dispositivo: 768px) e (altura do dispositivo: 1024px) e (orientação: paisagem) {
    .foo {
        altura: 768px;
    }
}
                                               
/ * iPhone 5
Você também pode segmentar dispositivos com proporção. * / @ tela de mídia e (relação de aspecto do dispositivo: 40/71) {
    .foo {
        altura: 500 px;
    }
}

Observando o código acima, parece que uma leve sobreposição de conteúdo é inevitável. No entanto, os elementos com posicionamento e dimensionamento que dependem das unidades de viewport permaneceriam constantes. Isso é uma vitória! Adicionar algo como um simples calc (100vh - heightOfBar) compensaria a barra de endereço. Mas com tantos dispositivos e navegadores para oferecer suporte, isso não parece uma solução sustentável.

Solução 2: Segmentando innerHeight com Javascript.

As medidas internas se referem à altura / largura da janela de visualização, levando em consideração as barras de rolagem vertical / horizontal. Agora estamos a falar! Aqui está um diagrama do que isso implica.

Usando esse conhecimento, você pode usar um script simples como este para definir a altura no carregamento da página e mantê-la constante até o redimensionamento, do usuário do Stack Overflow tobiq:

window.onresize = function () {
    document.body.height = window.innerHeight;
}
window.onresize (); // chamado para definir inicialmente a altura.

Solução 3: Componente de reação Div100vh

Como todos gostamos do React, eu queria encontrar uma solução para o React Components. Encontrei um pacote npm de Mikhail Vasin que visa corrigir esse problema. Instale da seguinte forma:

npm install --save react-div-100vh

Em seguida, importe o componente e envolva seus elementos nele, como:

importar Div100vh de 'react-div-100vh';
const MyFullscreenComponent = () => (
    
       Suas coisas vão aqui
    
)

E lá vai você!

Após testar essas várias soluções, percebo que não há uma solução única para esse problema. Portanto, seja diligente com seu teste entre navegadores e dispositivos diferentes. E talvez evite usar unidades vh / vw para dispositivos móveis, pois o comportamento de buggy com essas unidades está bem documentado nos navegadores móveis.

Deixe-me saber se essas soluções foram úteis para você e quais funcionaram melhor!