Imagens fáceis de DPI alto

Telas com alta densidade de pixels estão rapidamente se tornando a norma. Os criadores de conteúdo precisam se adaptar a esse fato. Este é um guia rápido sobre como veicular imagens de alta qualidade na Web atualmente, sem polyfills, JavaScript, invasões de CSS e recursos de navegador que ainda não foram implementados. Em uma palavra: sem mudanças drásticas no fluxo de trabalho.

Hoje, há muitas propostas de imagens responsivas, e muitas delas envolvem mudanças significativas para o desenvolvedor da Web. O atributo srcset <img> da faixa de padrões é difícil de implementar, especialmente com a complexidade da seleção extra de srcset com base na janela de visualização:

banner-HD.jpeg 2x, banner-phone.jpeg 100w, banner-phone-HD.jpeg 100w 2x

Embora a propriedade CSS image-set use apenas devicePixelRatio para decidir qual imagem carregar, ela ainda força os desenvolvedores a criar muitas marcações extras para cada imagem.

Outras propostas, como o elemento <picture>, são ainda mais detalhadas. Além disso, eles não são padrões, então a disponibilidade ubíqua deles é ainda maior do que o atributo srcset. As soluções JavaScript e do lado do servidor são a única outra alternativa, mas essas abordagens têm desvantagens próprias, conforme abordadas em outros artigos.

Este artigo aborda vários usos de imagens comumente encontradas na Web e propõe soluções simples que funcionam em telas com alta densidade de pixels e também em telas comuns. Para os fins desta discussão, qualquer dispositivo que informe window.devicePixelRatio maior que 1 pode ser considerado de alta DPI, já que isso significa que os pixels CSS não são iguais aos pixels do dispositivo e que as imagens estão sendo dimensionadas.

Veja a seguir um resumo:

  • Use CSS/SVG em vez de imagens rasterizadas, se possível.
  • Use imagens otimizadas para telas de alta densidade por padrão.
  • Use PNGs para desenhos simples e pixel art, como logotipos.
  • Use JPEGs compactados para imagens com várias cores (por exemplo, fotos).
  • Sempre defina tamanhos explícitos (usando CSS ou HTML) em todos os elementos de imagem.

Desenhos simples e pixel art

Imagens pequenas muitas vezes podem ser totalmente evitadas com o uso de recursos CSS ou SVG. Por exemplo, não é necessário usar imagens para cantos arredondados, já que a propriedade CSS border-radius tem suporte amplo. Da mesma forma, as fontes personalizadas são amplamente aceitas, portanto, não é recomendável usar texto com "imagem".

No entanto, em alguns casos, como logotipos, uma imagem pode ser a única maneira de avançar. Por exemplo, este logotipo do Chrome tem um tamanho natural de 256 x 256. Em uma tela Retina, é possível ver o aliasing de linha em diagonais e curvas, que parece irregular e ruim, especialmente quando comparado ao texto renderizado com nitidez:

Chrome 1x
PNG 1x

Dimensões naturais: 256x256px, tamanho do recurso: 31 kB, formato: PNG

Convencido? Certo? Agora vamos usar uma imagem de alta densidade. Você pode querer economizar espaço armazenando seu logotipo como um JPEG, mas isso não é uma boa ideia, já que salvar logotipos e outros gráficos em um formato com perda tende a introduzir artefatos. Nesse caso, exagerei o problema usando uma compressão muito alta, mas observe as faixas nos gradientes, as manchas em fundos brancos e as linhas bagunçadas:

Chrome 2x
Jpeg 2x

Dimensões naturais: 512x512px, tamanho do recurso: 13 kB, formato: JPEG

O que deve ser feito para imagens relativamente pequenas é usar PNGs de 2x. A diferença de tamanho entre um PNG 1x e 2x geralmente é bastante alta (52 kB, neste caso). No entanto, no caso de um logotipo, ele é a identidade do seu site e a primeira coisa que os visitantes vão notar. Ao reduzir muito a qualidade em troca de tamanho, isso também será a última coisa que os visitantes verão.

Este é o logotipo do Chrome em toda a sua glória, reduzido à metade das dimensões naturais para telas 2x:

Chrome 2x
Png 2x

Dimensões naturais: 512x512px, tamanho do recurso: 83 kB, formato: PNG

A marcação para renderizar a imagem acima é a seguinte:

<img src="chrome2x.png" style="width: 256px; height: 256px;"/>

Observe que eu especifiquei uma largura e uma altura na imagem. Isso é necessário porque o tamanho natural da imagem é de 512 px. Isso também é bom para a performance porque o mecanismo de renderização tem uma boa compreensão do tamanho do elemento e não precisa trabalhar muito para calculá-lo.

Uma otimização possível que pode funcionar é reduzir o PNG de 24 bits para um de 8 bits com paletas. Isso funciona para imagens com um pequeno número de cores, incluindo o logotipo do Chrome. Para fazer essa otimização, use uma ferramenta como http://pngquant.org/. Você pode notar um pouco de faixas aqui, mas esse arquivo tem apenas 13 kB, o que é uma economia de tamanho de 6x em comparação com o PNG de 512 x 512 original.

Chrome 2x 8 bits
PNG 2x8 bits

Dimensões naturais: 512x512px, tamanho do recurso: 13 kB, formato: PNG, 8-bit palette

Imagens com uma variedade de cores

Escrevi um artigo da HTML5Rocks pesquisando várias técnicas diferentes de imagem responsiva e pesquisei sobre a compactação de JPEG 1x e 2x e comparando os tamanhos resultantes e a qualidade visual. Confira um desses blocos do artigo acima:

.

Eu rotulei as imagens com o nível de compactação (indicado pela qualidade JPEG), o tamanho (em bytes) e minha opinião subjetiva sobre a fidelidade visual comparativa (classificada por números). O interessante aqui é que a imagem 2x altamente compactada (identificada como 3) é menor em tamanho e tem uma aparência melhor do que a imagem 1x não compactada (identificada como 4). Em outras palavras, entre as imagens 4 e 3, conseguimos melhorar a qualidade da imagem dobrando cada dimensão e aumentando significativamente a compactação, ao mesmo tempo que reduzimos o tamanho em 2 KB.

Compactação, dimensões e qualidade visual

Eu queria saber um pouco mais sobre as compensações entre nível de compactação, dimensões, qualidade visual e tamanho da imagem. Realizei um estudo com a seguinte hipótese com base no estudo acima:

Hipótese

Com compressão suficiente, uma imagem de 2x vai parecer equivalente à mesma imagem no tamanho 1x com outra compressão (menor). No entanto, nesse caso, a imagem de 2x altamente compactada será menor em tamanho do que a imagem de 1x.

Processo

  • Com uma imagem de 2x, gere a de 1x.
  • Compacte as duas imagens em vários níveis.
  • Crie uma página de teste que mostre os dois conjuntos de imagens lado a lado.
  • Nos dois conjuntos, encontre o lugar em que as imagens são equivalentes.
  • Observe os tamanhos de imagem e os níveis de compactação equivalentes.
  • Teste em telas de 1x e 2x.

Eu criei um app de comparação de imagens lado a lado semelhante à visualização de comparação do Lightroom. A intenção é mostrar imagens de 1x e 2x lado a lado, mas também permitir que você amplie qualquer seção da imagem para conferir mais detalhes. Você também pode selecionar entre os formatos JPEG e WebP e mudar a qualidade da compactação para conferir comparações de tamanho de arquivo e qualidade de imagem. A ideia é ajustar as configurações de várias imagens, descobrir qual é a diferença entre qualidade de compactação, dimensionamento e formato e qualidade da imagem, e usar essa configuração para todas as imagens.

Captura de tela de comparação

A ferramenta está disponível para você brincar. Para aumentar o zoom da imagem, selecione uma subárea para aumentar o zoom.

Análise

A qualidade da imagem é algo subjetivo. Além disso, seu caso de uso específico provavelmente vai determinar onde suas prioridades estão no espectro de fidelidade visual e tamanho do arquivo. Além disso, diferentes tipos de recursos de imagem reagem de forma diferente à qualidade do escalonamento e da compactação, portanto, uma solução única pode não funcionar necessariamente aqui. O objetivo da ferramenta é ajudar você a criar uma intuição para compactações, escalas e formatos de qualidade de imagem.

Ao brincar com o zoom de imagem, algumas coisas rapidamente ficaram aparentes para mim. Primeiro, prefiro quality=30 dpr=2x a quality=90 dpr=1x imagens para aumentar os detalhes. Essas imagens também são comparáveis em tamanho de arquivo (no caso do avião, a imagem compactada de 2x é de 76 KB, enquanto a não compactada de 1x é de 80 KB).

As exceções a essa regra são imagens altamente compactadas (quality<30) com gradientes. Elas tendem a sofrer de faixas de cores, o que é igualmente ruim independente da escala da imagem. As amostras de pássaros e carros encontradas na ferramenta são exemplos disso.

As imagens WebP são muito mais limpas do que JPEG, especialmente em níveis de compactação baixos. Essa faixa de cores não parece um problema. Por fim, as imagens WebP são muito mais compactas.

Advertências e conclusão

Fazer com que as imagens fiquem bonitas em telas de alta densidade é apenas metade dos problemas relacionados à imagem causados por uma grande variação nas telas. Em alguns casos, talvez seja melhor veicular imagens totalmente diferentes, dependendo do tamanho da janela de visualização. Por exemplo, a foto do rosto de Obama pode ser adequada para uma tela do tamanho de um smartphone, mas o suporte na frente dele e uma bandeira atrás dele e alguns podem ser mais adequados para uma tela de laptop.

Eu evitei deliberadamente este tópico de "direção de arte" para me concentrar apenas em imagens de alta DPI. Esse problema pode ser resolvido com várias abordagens diferentes: usando consultas de mídia e imagens de plano de fundo, via JavaScript, com alguns novos recursos, como image-set, ou no servidor. Este tópico é abordado em Imagens de DPI alto para densidades de pixels variáveis.

Vou encerrar com alguns problemas em aberto:

  • Efeitos da alta compressão no desempenho. Quais são as penalidades de decodificar imagens altamente compactadas?
  • Quais são as penalidades de desempenho de ter que redimensionar a imagem para baixo quando uma imagem de 2x é carregada em uma tela de 1x?

Em resumo, use CSS e SVG em vez de imagens rasterizadas. Se imagens raster forem estritamente necessárias, use PNGs para imagens com uma paleta limitada e muitas cores sólidas e use JPEGs para imagens com muitas cores e gradientes. A vantagem dessa abordagem é que sua marcação é praticamente inalterada. O desenvolvedor Web só precisa gerar o dobro de recursos e dimensionar as imagens corretamente no DOM.

Para saber mais, confira o artigo de Scott Jehl (em inglês) sobre um tema semelhante. Que suas imagens fiquem nítidas e que o uso de dados da rede celular seja baixo.