WebView com pixels perfeitos

Publicado em 28 de fevereiro de 2014

Há várias opções que você pode usar para criar a interface perfeita para sua WebView.

Definir a metatag viewport

A metatag de viewport é uma das tags mais importantes a serem adicionadas ao seu app da Web. Sem ela, a WebView pode agir como se o site fosse projetado para navegadores de computador. Isso faz com que a página da Web receba uma largura maior (normalmente 980 px) e a redimensiona para caber na largura da WebView. Na maioria dos casos, isso resulta em uma pequena versão geral da página que exige que o usuário faça a panorâmica e o zoom para ler o conteúdo.

Se você quiser que a largura do seu site seja 100% da largura da WebView, configure a metatag da janela de visualização:

<meta name="viewport" content="width=device-width, initial-scale=1">

Defina a largura como o valor especial device-width para ter mais controle sobre o layout da página.

Por padrão, a WebView define a janela de visualização como "device-width", em vez de definir como padrão uma janela de visualização para computador. No entanto, para um comportamento confiável e controlado, é recomendável incluir a metatag de viewport.

Mostrar sites para computador

Em alguns casos, talvez seja necessário mostrar conteúdo que não foi projetado para dispositivos móveis. Por exemplo, você pode exibir conteúdo que não controla. Nesse caso, é possível forçar a WebView a usar uma janela de visualização do tamanho de um computador:

Se esses métodos não forem definidos e nenhuma viewport for especificada, a WebView tentará definir a largura da viewport com base no tamanho do conteúdo.

Além disso, você pode usar o algoritmo de layout TEXT_AUTOSIZING, que aumenta o tamanho da fonte para torná-la mais legível em um dispositivo móvel. Consulte setLayoutAlgorithm.

Usar design responsivo

O design responsivo é uma abordagem para projetar uma interface que muda de acordo com o tamanho da tela.

Há várias maneiras de implementar o design responsivo. Uma das mais comuns é a consulta @media, que aplica CSS a elementos com base nas características de um dispositivo.

Por exemplo, suponha que você queira mudar de um layout vertical para um horizontal com base na orientação. Defina as propriedades do CSS como padrão para retrato:

.page-container {
    display: -webkit-box;
    display: flex;

    -webkit-box-orient: vertical;
    flex-direction: column;

    padding: 20px;
    box-sizing: border-box;
}

Para alternar para um layout horizontal, alterne a propriedade flex-direction com base na orientação:

@media screen and (orientation: landscape) {
  .page-container.notification-opened {
    -webkit-box-orient: horizontal;
    flex-direction: row;
  }

  .page-container.notification-opened > .notification-arrow {
    margin-right: 20px;
  }
}

Também é possível mudar o layout com base na largura da tela.

Por exemplo, ajustar o tamanho da largura do botão de 100% para algo menor à medida que o tamanho físico da tela aumenta.

button {
  display: block;
  width: 100%;
  ...
}

@media screen and (min-width: 500px) {
  button {
    width: 60%;
  }
}

@media screen and (min-width: 750px) {
  button {
    width: 40%;
    max-width: 400px;
  }
}

Essas são mudanças menores, mas, dependendo da sua interface, as consultas de mídia podem ajudar a fazer mudanças muito maiores na aparência do seu aplicativo, mantendo o mesmo HTML.

Imagens nítidas

A variedade de tamanhos e densidades de tela também apresenta desafios para as imagens. Imagens menores exigem menos memória e são carregadas mais rapidamente, mas ficam desfocadas se você aumentar o tamanho delas.

Confira algumas dicas e truques para garantir que suas imagens fiquem nítidas em qualquer tela:

  • Use CSS para efeitos escalonáveis.
  • Use gráficos vetoriais.
  • Envie fotos em alta resolução.

Usar CSS para efeitos escalonáveis

Use CSS sempre que possível, em vez de imagens. É possível que algumas combinações de propriedades CSS sejam caras para renderizar. Sempre teste as combinações específicas que você está usando.

Saiba mais sobre a First Contentful Paint (FCP), que mede o tempo entre o momento em que o usuário navegou pela primeira vez até o momento em que qualquer parte do conteúdo da página é renderizada na tela. "Conteúdo" se refere a texto, imagens (incluindo imagens de plano de fundo), elementos <svg> e elementos <canvas> que não sejam brancos.

Usar gráficos vetoriais

Os elementos gráficos vetoriais escaláveis (SVGs) são uma ótima maneira de fornecer uma imagem escalável. Para imagens adequadas a gráficos vetoriais, o SVG oferece imagens de alta qualidade com tamanhos de arquivo muito pequenos.

Fornecer fotos de alta resolução

Use uma foto adequada para um dispositivo de alta DPI e dimensione a imagem usando CSS. Dessa forma, a imagem pode ser renderizada com alta qualidade em todos os dispositivos. Se você usar uma compressão alta (configuração de baixa qualidade) ao gerar a imagem, poderá conseguir bons resultados visuais com um tamanho de arquivo razoável.

Essa abordagem tem algumas desvantagens: imagens altamente compactadas podem mostrar alguns artefatos visuais. Portanto, é necessário testar para determinar qual nível de compactação você considera aceitável. E redimensionar a imagem em CSS pode ser uma operação cara.

Se a compactação alta não for adequada para suas necessidades, tente o formato WebP, que oferece uma imagem de alta qualidade com um tamanho de arquivo relativamente pequeno. Não se esqueça de fornecer um substituto para versões do Android que não oferecem suporte à WebP.

Controle granular

Em muitos casos, não é possível usar uma única imagem para todos os dispositivos. Nesse caso, é possível selecionar imagens diferentes com base no tamanho e na densidade da tela. Use media queries para selecionar imagens de plano de fundo por tamanho e densidade da tela.

Você pode usar o JavaScript para controlar como as imagens são carregadas, mas isso aumenta a complexidade.

Consultas de mídia e densidade da tela

Para selecionar uma imagem com base na densidade da tela, use unidades dpi ou dppx na consulta de mídia. A unidade dpi representa pontos por polegada CSS, e dppx representa pontos por pixel CSS.

Na tabela a seguir, você pode conferir a relação entre dpi e dppx.

Proporção de pixels do dispositivo Densidade de tela generalizada Pontos por polegada CSS (dpi) Pontos por pixel CSS (dppx)
1 x MDPI 96dpi 1dppx
1,5x HDPI 144dpi 1,5dppx
2 XHDPI 192dpi 2dppx

Os buckets de densidade de tela generalizados são definidos pelo Android e usados em outros lugares para expressar a densidade da tela (por exemplo, https://screensiz.es).

Imagens de plano de fundo

Você pode usar consultas de mídia para atribuir imagens de plano de fundo a elementos. Por exemplo, se você tiver uma imagem de logotipo com tamanho de 256 x 256 pixels em um dispositivo com uma proporção de pixel de 1,0, use as seguintes regras de CSS:

.welcome-header > h1 {
  flex: 1;

  width: 100%;

  max-height: 256px;
  max-width: 256px;

  background-image: url('../images/html5_256x256.png');
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

Para trocar por uma imagem maior em dispositivos com uma proporção de pixels de 1,5 (hdpi) e 2,0 (xhdpi), adicione as seguintes regras:

@media screen and (min-resolution: 1.5dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_384x384.png');
  }
}

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

Você pode mesclar essa técnica com outras consultas de mídia, como min-width, que é útil para considerar diferentes formatos.

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

@media screen and (min-resolution: 2dppx) and (min-width: 1000px) {
  .welcome-header > h1{
    background-image: url('../images/html5_1024x1024.png');

    max-height: 512px;
    max-width: 512px;
  }
}

Você pode notar que max-height e max-width estão definidos como 512px para resolução de 2ddpx, com uma imagem de 1024x1024px. Isso ocorre porque um "pixel" do CSS leva em conta a proporção de pixels do dispositivo (512px * 2 = 1024px).

E o <img/>?

A Web ainda não tem uma solução para isso. Há algumas propostas, mas elas não estão disponíveis nos navegadores atuais ou na WebView.

Enquanto isso, se você gerar seu DOM em JavaScript, poderá criar vários recursos de imagem em uma estrutura de diretório bem pensada:

images/
  mdpi/
    imagename.png
  hdpi/
    imagename.png
  xhdpi/
    imagename.png

Em seguida, use a proporção de pixels para tentar extrair a imagem mais adequada:

function getDensityDirectoryName() {
  if(!window.devicePixelRatio) {
    return 'mdpi';
  }

  if(window.devicePixelRatio > 1.5) {
    return 'xhdpi';
  } else if(window.devicePixelRatio > 1.0) {
    return 'hdpi';
  }

  return 'mdpi';
}

Como alternativa, você pode alterar o URL base da página para definir os URLs relativos de imagens.

<!doctype html>
<html class="no-js">
<head>
  <script>
    function getDensityDirectoryName() {
      if(!window.devicePixelRatio) {
          return 'mdpi';
      }

      if(window.devicePixelRatio > 1.5) {
          return 'xhdpi';
      } else if(window.devicePixelRatio > 1.0) {
          return 'hdpi';
      }

      return 'mdpi';
    }

    var baseUrl =
        'file:///android_asset/www/img-js-diff/ratiores/'+getDensityDirectoryName()+'/';
    document.write('<base href="'+baseUrl+'">');
  </script>

    ...
</head>
<body>
    ...
</body>
</html>

Essa abordagem bloqueia o carregamento da página e força o uso de caminhos absolutos para todos os recursos, como imagens, scripts e arquivos CSS, já que o URL base aponta para um diretório específico de densidade.