Como otimizar seu site HTML5

Introdução

Atualmente, o desenvolvimento para a web para dispositivos móveis é um tema importante. Este ano, pela primeira vez, os smartphones venderam PCs. Cada vez mais usuários estão usando dispositivos móveis para navegar na Web, o que significa que é fundamental que os desenvolvedores otimizem os sites para navegadores móveis.

O campo de batalha do "dispositivo móvel" ainda é desconhecido para um grande número de desenvolvedores. Muitas pessoas têm sites legados que negligenciam completamente os usuários de dispositivos móveis. Em vez disso, o site foi projetado principalmente para a navegação em computadores e é prejudicado em navegadores para dispositivos móveis. Este site (html5rocks.com) não é exceção. No lançamento, fizemos pouco esforço para criar uma versão do site para dispositivos móveis.

Como criar um site html5rocks.com compatível com dispositivos móveis

Como exercício, pensei que seria interessante usar o html5rocks (um site HTML5 existente) e ampliá-lo com uma versão compatível com dispositivos móveis. O que me preocupava principalmente com o mínimo de trabalho necessário O objetivo do meu exercício não era criar um site móvel totalmente novo e manter duas bases de código. Isso levaria muito tempo e seria uma grande perda de tempo. Já tínhamos definido a estrutura do site (marcação). Temos uma visão geral (CSS). A funcionalidade principal (JS) estava lá. A questão é que muitos sites estão nesse mesmo barco.

Este artigo examina como criamos uma versão móvel do html5rocks otimizada para dispositivos Android e iOS. Basta carregar o html5rocks.com em um dispositivo compatível com um desses sistemas operacionais para ver a diferença. Não existem redirecionamentos para um m.html5rocks.com ou outra tolerância dessa natureza. Você aproveita o html5rocks sem mudanças, com a vantagem de ter uma ótima aparência e que funciona bem em dispositivos móveis.

html5rocks.com para computadores html5rocks.com para dispositivos móveis
html5rocks.com no computador (à esquerda) e dispositivo móvel (à direita)

Consultas de mídia CSS

O HTML4 e o CSS2 são compatíveis com folhas de estilo dependentes de mídia (link em inglês) há algum tempo. Exemplo:

<link rel="stylesheet" media="print" href="printer.css">

segmentaria dispositivos de impressão e forneceria um estilo específico para o conteúdo da página quando ele fosse impresso. O CSS3 leva a ideia de tipos de mídia um passo adiante e aprimora sua funcionalidade com consultas de mídia. As consultas de mídia estendem a utilidade dos tipos de mídia, permitindo uma rotulagem mais precisa das folhas de estilo. Isso permite que a apresentação do conteúdo seja personalizada para um intervalo específico de dispositivos de saída sem precisar mudar o conteúdo. Isso parece perfeito para um layout que precisa ser modificado!

Você pode usar consultas de mídia no atributo media das folhas de estilo externas para segmentar a largura da tela, a largura do dispositivo, a orientação etc. Para ver a lista completa, consulte a especificação de consulta de mídia W3C.

Segmentação de tamanhos de tela

No exemplo a seguir, phone.css se aplica a dispositivos que o navegador considera "portáteis" ou dispositivos com telas <= 320 px de largura.

 <link rel='stylesheet'
  media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>

Prefixar uma consulta de mídia com a palavra-chave "only" fará com que navegadores não compatíveis com CSS3 ignorem a regra.

O código a seguir segmenta tamanhos de tela entre 641 e 800 pixels:

 <link rel='stylesheet'
  media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>

As consultas de mídia também podem aparecer em tags <style> inline. O código abaixo é direcionado a tipos de mídia all na orientação retrato:

 <style>
  @media only all and (orientation: portrait) { ... }
 </style>

media="handheld"

Precisamos parar por um minuto e conversar sobre media="handheld". O fato é que o Android e o iOS ignoram media="handheld". A alegação é que os usuários não terão o conteúdo sofisticado fornecido pelas folhas de estilo segmentadas para media="screen", e é menos provável que os desenvolvedores mantenham uma versão de media="handheld" de qualidade mais baixa. Assim, como parte do lema "Web completa", a maioria dos navegadores modernos para smartphones simplesmente ignora as folhas de estilo portáteis.

Seria ideal usar esse recurso para segmentar dispositivos móveis, mas vários navegadores o implementaram de maneiras diferentes:

  • Alguns leem apenas a folha de estilo portátil.
  • Alguns leem apenas a folha de estilo portátil, se houver uma, mas, caso contrário, usam como padrão a folha de estilos da tela.
  • Alguns leem a folha de estilos portátil e a folha de estilos da tela.
  • Alguns leem apenas a folha de estilos da tela.

O Opera Mini não ignora media="handheld". O truque para fazer o Windows Mobile reconhecer media="handheld" é usar letras maiúsculas no valor do atributo de mídia para a folha de estilo da tela:

 <!-- media="handheld" trick for Windows Mobile -->
 <link rel="stylesheet" href="screen.css" media="Screen">
 <link rel="stylesheet" href="mobile.css" media="handheld">

Como o html5rocks usa consultas de mídia

As consultas de mídia são muito usadas em todo o site html5rocks para dispositivos móveis. Eles nos permitiram ajustar o layout sem ter que fazer mudanças significativas na marcação de modelo do Django... um verdadeiro salva-vidas! Além disso, a compatibilidade deles com vários navegadores é muito boa.

No <head> de cada página, você verá as seguintes folhas de estilo:

 <link rel='stylesheet'
  media='all' href='/static/css/base.min.css' />
 <link rel='stylesheet'
  media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />

A base.css sempre definiu a aparência principal do html5rocks.com, mas agora estamos aplicando novos estilos (mobile.css) para larguras de tela abaixo de 800 px. Sua consulta de mídia abrange smartphones (aproximadamente 320 pixels) e o iPad (aproximadamente 768 pixels). Efeito: estamos modificando gradualmente os estilos em base.css (somente conforme necessário) para melhorar a aparência em dispositivos móveis.

Algumas das mudanças de estilo aplicadas pelo mobile.css:

  • Reduz o espaço em branco/padding extra no site. Telas pequenas significam que o espaço é valioso!
  • Remove os estados :hover. Eles nunca serão vistos em dispositivos de toque.
  • Ajusta o layout para uma coluna única. Falaremos mais sobre isso depois.
  • Remove o box-shadow ao redor do div do contêiner principal do site. Sombras de caixas grandes reduzem o desempenho da página.
  • Usamos o modelo Flexbox box-ordinal-group do CSS para mudar a ordem de cada seção na página inicial. Você notará que "LEARN BY MAJOR HTML5 FEATURE GROUPS" vem antes da seção "TUTORIALS" na página inicial, mas depois dela na versão para dispositivos móveis. Essa ordem fazia mais sentido para dispositivos móveis e não exigiu mudanças na marcação. Flexbox CSS Ford!
  • Remove opacity mudanças. Em dispositivos móveis, a alteração dos valores Alfa afeta o desempenho.

Metatags para dispositivos móveis

O WebKit para dispositivos móveis é compatível com algumas novidades que oferecem aos usuários uma melhor experiência de navegação em determinados dispositivos.

Configurações da janela de visualização

A primeira configuração meta (e que você usará com mais frequência) é a propriedade da janela de visualização. A definição de uma janela de visualização informa ao navegador como o conteúdo deve caber na tela do dispositivo e informa que o site é otimizado para dispositivos móveis. Exemplo:

 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

instrui o navegador a definir a janela de visualização de acordo com a largura do dispositivo com uma escala inicial de 1. Esse exemplo também permite aplicar zoom, algo que pode ser desejável para um site, mas não para um app da Web. Podemos impedir o zoom com user-scalable=no ou limitar o dimensionamento até um determinado nível:

 <meta name=viewport
  content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">

O Android estende a metatag janela de visualização, permitindo que os desenvolvedores especifiquem para qual resolução de tela o site foi desenvolvido:

 <meta name="viewport" content="target-densitydpi=device-dpi">

Os valores possíveis para target-densitydpi são device-dpi, high-dpi, medium-dpi e low-dpi.

Caso queira modificar a página da Web para diferentes densidades de tela, use a consulta de mídia CSS -webkit-device-pixel-ratio e/ou a propriedade window.devicePixelRatio em JavaScript e defina a metatag target-densitydpi como device-dpi. Isso impede que o Android execute o dimensionamento na sua página da Web e permite que você faça os ajustes necessários para cada densidade, via CSS e JavaScript.

Consulte a documentação do WebView para mais informações sobre como segmentar resoluções de dispositivo.

Navegação em tela cheia

Existem dois outros valores meta que são específicos do iOS. apple-mobile-web-app-capable e apple-mobile-web-app-status-bar-style renderizam o conteúdo da página no modo de tela cheia semelhante a um app e tornam a barra de status translúcida:

 <meta name="apple-mobile-web-app-capable" content="yes">
 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

Para mais informações sobre todas as opções meta disponíveis, consulte a documentação de referência do Safari.

Ícones da tela inicial

Os dispositivos iOS e Android também aceitam um rel="apple-touch-icon" (iOS) e um rel="apple-touch-icon-precomposed" (Android) como links. Eles criam um ícone chamativo semelhante a um aplicativo na tela inicial do usuário quando ele adiciona seu site aos favoritos:

 <link rel="apple-touch-icon"
      href="/static/images/identity/HTML5_Badge_64.png" />
 <link rel="apple-touch-icon-precomposed"
      href="/static/images/identity/HTML5_Badge_64.png" />

Como o html5rocks usa metatags para dispositivos móveis

Para resumir tudo, veja um snippet da seção <head> do html5rocks:

 <head>
  ...
   <meta name="viewport"
        content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />

   <link rel="apple-touch-icon"
        href="/static/images/identity/HTML5_Badge_64.png" />
   <link rel="apple-touch-icon-precomposed"
        href="/static/images/identity/HTML5_Badge_64.png" />
  ...
 </head>

Layout vertical

Em telas menores, é muito mais conveniente rolar verticalmente do que horizontalmente. Ao manter o conteúdo em uma única coluna, o layout vertical é preferível para dispositivos móveis. Para o html5rocks, usamos consultas de mídia CSS3 para criar esse layout. Mais uma vez, sem alterar a marcação.

Índice de tutoriais. Tutorial. página &quot;Recurso HTML5&quot;. Página de perfis de autor.
Layout vertical de coluna única em todo o site.

Otimizações para dispositivos móveis

A maioria das otimizações que fizemos são coisas que deveriam ter sido feitas em primeiro lugar. Coisas como redução do número de solicitações de rede, compactação JS/CSS, gzipping (versão sem custo financeiro do App Engine) e minimização das manipulações de DOM. Essas técnicas são práticas recomendadas comuns, mas às vezes são negligenciadas ao apressar um site para lançar.

Ocultar a barra de endereço automaticamente

Os navegadores para dispositivos móveis não têm o espaço disponível na tela que seu correspondente para desktop. Para piorar, em diferentes plataformas, às vezes você acaba com uma grande barra de endereço na parte superior da tela, mesmo depois que a página termina de carregar.

Uma maneira fácil de lidar com isso é rolar a página usando JavaScript. Mesmo que isso seja feito por um pixel, a irritante barra de endereço vai ser resolvida. Para forçar a ocultação da barra de endereço no html5rocks, anexei um manipulador de eventos onload ao objeto window e rolei a página verticalmente em um pixel:

Barra de endereço.
A barra de endereço ocupa um espaço na tela.
  // Hides mobile browser's address bar when page is done loading.
  window.addEventListener('load', function(e) {
    setTimeout(function() { window.scrollTo(0, 1); }, 1);
  }, false);

Também unimos esse listener à variável de modelo is_mobile, já que ele não é necessário no computador.

Reduzir solicitações de rede, economizar largura de banda

Sabemos que a redução do número de solicitações HTTP pode melhorar muito o desempenho. Os dispositivos móveis limitam ainda mais o número de conexões simultâneas que o navegador pode fazer, então os sites para dispositivos móveis vão se beneficiar ainda mais da redução dessas solicitações irrelevantes. Além disso, a redução de cada byte é fundamental, porque a largura de banda costuma ser limitada em telefones. Isso pode estar custando dinheiro aos usuários!

Veja a seguir algumas das abordagens que adotamos para minimizar as solicitações de rede e reduzir a largura de banda no html5rocks:

  • Remover iframes: eles são lentos! Grande parte da nossa latência veio de widgets de compartilhamento de terceiros (Buzz, Google amigo Connect, Twitter, Facebook) nas páginas de tutorial. Essas APIs foram incluídas por meio de tags <script> e criam iframes que diminuem a velocidade da página. Os widgets foram removidos dos dispositivos móveis.

  • display:none: em alguns casos, ocultamos a marcação quando ela não se encaixava no perfil para dispositivos móveis. Um bom exemplo foram as quatro caixas arredondadas no topo da página inicial:

Botões de caixa na página inicial.
Botões de caixa na página inicial.

Eles não estão disponíveis no site móvel. É importante lembrar que o navegador ainda faz uma solicitação para cada ícone, mesmo que o contêiner esteja oculto com display:none. Portanto, não foi suficiente simplesmente ocultar esses botões. Além de desperdiçar largura de banda, o usuário nem veria os frutos dessa largura de banda desperdiçada. A solução foi criar um booleano "is_mobile" no nosso modelo Django para omitir condicionalmente seções de HTML. Quando o usuário visualiza o site em um dispositivo inteligente, os botões ficam de fora.

  • Cache de aplicativos: isso não só nos oferece suporte off-line, como também cria uma inicialização mais rápida.

  • Compactação CSS/JS: estamos usando o YUI Compressor em vez do Closure compilador, principalmente porque ele processa CSS e JS. Um problema que encontramos foi que as consultas de mídia in-line (consultas de mídia que aparecem em uma folha de estilo) eram exibidas no compressor YUI 2.4.2. Consulte este problema (link em inglês). Ao usar o YUI Compressor 2.4.4+, o problema foi corrigido.

  • Usamos sprites de imagem CSS sempre que possível.

  • O pngcrush foi usado para a compactação de imagens.

  • Foram usados URIs de dados para imagens pequenas. A codificação Base64 aumenta aproximadamente 30%do tamanho da imagem, mas salva a solicitação de rede.

  • A Pesquisa personalizada do Google foi carregada automaticamente usando uma única tag de script em vez de carregá-la dinamicamente com google.load(). O último faz uma solicitação extra.

<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
  • Nossa impressora de código e a Modernizr estavam sendo incluídas em todas as páginas, mesmo que nunca fossem usadas. O Modernizr é ótimo, mas executa vários testes em cada carga. Alguns desses testes fazem modificações caras no DOM e tornam o carregamento da página mais lento. Agora, só estamos incluindo essas bibliotecas nas páginas em que elas são realmente necessárias. - 2 solicitações :)

Outros ajustes de performance:

  • Movemos todo o arquivo JS para a parte de baixo da página (quando possível).
  • Tags <style> inline removidas.
  • Pesquisas de DOM em cache e minimizações das manipulações de DOM: sempre que você toca no DOM, o navegador realiza um reflow. Os reflows são ainda mais caros em um dispositivo móvel.
  • Descarregamos o código desnecessário do lado do cliente no servidor. Mais especificamente, a verificação define o estilo de navegação da página atual: js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } }.
  • Elementos com larguras fixas foram substituídos pelo fluido width:100% ou width:auto

Cache do aplicativo

A versão para dispositivos móveis do html5rocks usa o cache de aplicativo para acelerar o carregamento inicial e permite que os usuários leiam o conteúdo off-line.

Ao implementar o AppCache no site, é muito importante que você não armazene em cache o arquivo de manifesto, seja explicitamente no próprio arquivo de manifesto ou implicitamente com cabeçalhos de controle de cache pesados. Se o manifesto for armazenado em cache pelo navegador, a depuração será um pesadelo. O iOS e o Android fazem um trabalho particularmente bom ao armazenar esse arquivo em cache, mas não oferecem uma maneira conveniente de limpar o cache, como os navegadores de computador fazem.

Para impedir esse armazenamento em cache no nosso site, primeiro definimos o App Engine para nunca armazenar arquivos de manifesto em cache:

- url: /(.*\.(appcache|manifest))
  static_files: \1
  mime_type: text/cache-manifest
  upload: (.*\.(appcache|manifest))
  expiration: "0s"

Em segundo lugar, usamos a API JS para informar o usuário quando o download de um novo manifesto for concluído. É necessário atualizar a página:

window.applicationCache.addEventListener('updateready', function(e) {
  if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    window.applicationCache.swapCache();
    if (confirm('A new version of this site is available. Load it?')) {
      window.location.reload();
    }
  }
}, false);

Para economizar tráfego de rede, mantenha seu manifesto simples. Ou seja, não chame todas as páginas do site. Basta listar as imagens importantes, os arquivos CSS e JavaScript. A última coisa que você quer fazer é forçar o navegador móvel a fazer o download de um grande número de recursos em cada atualização do appcache. Em vez disso, lembre-se de que o navegador armazena implicitamente uma página html em cache quando o usuário a visita (e inclui um atributo <html manifest="...">).