Publicado em 22 de agosto de 2012 e atualizado pela última vez em 14 de abril de 2025
Com tantos dispositivos no mercado, há uma gama muito ampla de densidades de pixels da tela disponíveis. Os desenvolvedores de aplicativos precisam oferecer suporte a uma variedade de densidades de pixel, o que pode ser bastante desafiador. Na Web para dispositivos móveis, os desafios são agravados por vários fatores:
- Grande variedade de dispositivos com formatos diferentes.
- Largura de banda de rede e duração da bateria limitadas.
Em termos de imagens, o objetivo dos desenvolvedores da Web é oferecer as imagens de melhor qualidade da maneira mais eficiente possível. Aqui, abordamos algumas técnicas úteis para fazer isso agora e no futuro.
Evite imagens sempre que possível
Antes de presumir que você precisa incluir uma imagem, lembre-se de que a Web tem várias
tecnologias poderosas que são independentes da resolução e do DPI.
Especificamente, texto, SVG e grande parte do CSS "funcionam" devido ao
recurso de escalonamento automático de pixels da Web com
devicePixelRatio
.
No entanto, nem sempre é possível evitar imagens raster. Por exemplo, você pode receber recursos que seriam muito difíceis de replicar em SVGs ou CSS puros. Você pode estar lidando com uma fotografia. Embora seja possível converter uma imagem em um SVG automaticamente, a vetorização de fotografias não faz muito sentido porque as versões ampliadas geralmente não ficam boas.
Histórico da densidade de pixels
No início, as telas de computador tinham uma densidade de pixel de 72 ou 96 pontos por polegada (DPI).
As telas melhoraram gradualmente na densidade de pixels, em grande parte impulsionadas pelo avanço dos dispositivos móveis, já que os usuários geralmente seguram os smartphones mais perto do rosto, tornando os pixels mais visíveis. Em 2008, os smartphones de 150 dpi eram a nova norma. A densidade da tela continuou aumentando, e os smartphones atuais têm telas de 300 dpi.
Na prática, as imagens de baixa densidade precisam ter a mesma aparência nas novas telas que nas antigas, mas, em comparação com as imagens nítidas de alta densidade que os usuários estão acostumados a ver, as imagens de baixa densidade parecem irregulares e pixeladas. Confira abaixo uma simulação aproximada de como uma imagem 1x parece em uma tela 2x. Em contraste, a imagem 2x parece muito boa.
1x pixels | 2 pixels |
![]() |
![]() |
Pixels na Web
Quando a Web foi projetada, 99% das telas tinham 96 dpi, e poucas provisões foram feitas para variações. Agora que temos uma grande variação nos tamanhos e densidades de tela, precisamos de uma maneira padrão para que as imagens fiquem bonitas em todas elas.
A especificação HTML resolveu esse problema definindo um pixel de referência que os fabricantes usam para determinar o tamanho de um pixel CSS.
Usando o pixel de referência, um fabricante pode determinar o tamanho do pixel físico do dispositivo em relação ao pixel padrão ou ideal. Essa proporção é chamada de proporção de pixels do dispositivo.
Calcular a proporção de pixels do dispositivo
Suponha que um smartphone tenha uma tela com um tamanho físico de pixel de 180 pixels por polegada (ppi). Para calcular a proporção de pixels do dispositivo, siga estas etapas:
Compare a distância real em que o dispositivo é mantido com a distância do pixel de referência.
De acordo com a especificação, sabemos que, a 28 polegadas, o ideal é 96 pixels por polegada. Sabemos que, com um smartphone, os rostos das pessoas ficam mais próximos dos dispositivos do que com laptops e computadores desktop. Para as equações a seguir, estimamos essa distância em 45 cm.
Multiplique a proporção de distância pela densidade padrão (96 ppi) para conseguir a densidade de pixels ideal para a distância especificada.
idealPixelDensity = (28/18) * 96 = 150 pixels por polegada (aproximadamente)
Use a proporção da densidade física de pixels em relação à densidade ideal de pixels para encontrar a proporção de pixels do dispositivo.
devicePixelRatio = 180/150 = 1,2

Assim, quando um navegador precisa saber como redimensionar uma imagem para ajustar à tela, de acordo com a resolução ideal ou padrão, ele se refere à proporção de pixels do dispositivo de 1,2. Isso significa que, para cada pixel ideal, esse dispositivo tem 1,2 pixels físicos. A fórmula para alternar entre pixels ideais (conforme definido pela especificação da Web) e físicos (pontos na tela do dispositivo) é a seguinte:
physicalPixels = window.devicePixelRatio * idealPixels
Historicamente, os fornecedores de dispositivos tendem a arredondar devicePixelRatios
(DPRs, na sigla em inglês). O iPhone e o iPad da Apple informam um DPR de 1, e os equivalentes
da Retina informam 2. A especificação do CSS recomenda que
A unidade de pixel se refere ao número inteiro de pixels do dispositivo que mais se aproxima do pixel de referência.
Uma das razões pelas quais as proporções arredondadas podem ser melhores é porque elas podem levar a menos artefatos de subpixel.
No entanto, a realidade do cenário de dispositivos é muito mais variada, e os smartphones Android geralmente têm DPRs de 1,5. O tablet Nexus 7 tem um DPR de ~1,33, que foi alcançado por um cálculo semelhante ao exemplo anterior. No futuro, mais dispositivos vão ter DPRs variáveis. Por isso, nunca presuma que seus clientes têm DPRs inteiros.
Técnicas de imagem HiDPI
Há muitas técnicas para resolver o problema de mostrar as imagens de melhor qualidade o mais rápido possível, que se dividem em duas categorias:
- Otimizar imagens únicas.
- Otimização da seleção entre várias imagens.
Abordagens de imagem única: use uma imagem, mas faça algo inteligente com ela. Essas abordagens têm a desvantagem de que você precisa sacrificar a performance, já que precisa fazer o download de imagens HiDPI, mesmo em dispositivos mais antigos com DPI mais baixo. Confira algumas abordagens para o caso de imagem única:
- Imagem HiDPI altamente compactada
- Formato de imagem totalmente incrível
- Formato de imagem progressiva
Várias abordagens de imagem: use várias imagens, mas faça algo inteligente para escolher qual delas será carregada. Essas abordagens têm uma sobrecarga inerente para que o desenvolvedor crie várias versões do mesmo recurso e, em seguida, descubra uma estratégia de decisão. As opções são:
- JavaScript
- Entrega do lado do servidor
- Consultas de mídia CSS
- Recursos integrados do navegador (
image-set()
,<img srcset>
)
Imagem HiDPI altamente compactada
As imagens já representam 60% da largura de banda usada para fazer o download de um site médio. Ao exibir imagens HiDPI para todos os clientes, aumentamos esse número. Quanto maior ela pode ficar?
Fiz alguns testes que geraram fragmentos de imagem 1x e 2x com qualidade JPEG de 90, 50 e 20.
Com base nessa amostra pequena e não científica, parece que a compactação de imagens grandes oferece uma boa relação entre qualidade e tamanho. Para mim, as imagens compactadas de 2x ficam melhores do que as imagens de 1x não compactadas.
No entanto, veicular imagens de baixa qualidade e altamente compactadas para dispositivos 2x
é pior do que veicular imagens de maior qualidade. Essa abordagem
resultaria em penalidades de qualidade de imagem. Se você comparar imagens quality: 90
com imagens quality: 20
, haverá uma queda na nitidez da imagem
e um aumento da granulação. Artefatos com quality:20
podem não ser aceitáveis
em casos em que imagens de alta qualidade são importantes (por exemplo, um aplicativo de visualização
de fotos) ou para desenvolvedores de apps que não querem fazer concessões.
Essa comparação foi feita inteiramente com JPEGs compactados. Vale a pena observar que há muitas compensações entre os formatos de imagem amplamente implementados (JPEG, PNG, GIF), o que nos leva a…
WebP: formato de imagem totalmente incrível
O WebP é um formato de imagem atraente que compacta muito bem, mantendo a alta fidelidade da imagem.
Uma maneira de verificar o suporte ao WebP é usando JavaScript. Carregue uma imagem de 1 px
com data-uri
, aguarde o disparo de eventos de carregamento ou de erro e
verifique se o tamanho está correto. O Modernizr é enviado com
um script de detecção de recursos, que está disponível
com Modernizr.webp
.
No entanto, uma maneira melhor de fazer isso é diretamente no CSS usando a função image(). Portanto, se você tiver uma imagem WebP e um substituto JPEG, poderá escrever o seguinte:
#pic {
background: image("foo.webp", "foo.jpg");
}
Essa abordagem tem alguns problemas. Primeiro, image()
não é
amplamente implementado. Em segundo lugar, embora a compactação WebP supere o JPEG,
ela ainda é uma melhoria incremental,
cerca de 30% menor com base nesta galeria WebP (link em inglês). Portanto, o WebP
sozinho não é suficiente para resolver o problema de DPI alto.
Formatos de imagem progressiva
Formatos de imagem progressivos, como JPEG 2000, JPEG progressivo, PNG progressivo e GIF, têm o benefício (um tanto debatido) de mostrar a imagem antes de ela ser totalmente carregada. Eles podem incorrer em algum overhead de tamanho, embora haja evidências conflitantes sobre isso. Jeff Atwood afirmou que o modo progressivo "adiciona cerca de 20% ao tamanho das imagens PNG e cerca de 10% ao tamanho das imagens JPEG e GIF". No entanto, Stoyan Stefanov afirmou que, para arquivos grandes, o modo progressivo é mais eficiente (na maioria dos casos).
À primeira vista, as imagens progressivas parecem muito promissoras no contexto de veicular as imagens de melhor qualidade o mais rápido possível. A ideia é que o navegador possa parar de fazer o download e a decodificação de uma imagem quando saber que dados adicionais não vão aumentar a qualidade da imagem (ou seja, todas as melhorias de fidelidade são de subpixel).
Embora as conexões sejam encerradas rapidamente, elas geralmente são caras para reiniciar. Para um site com muitas imagens, a abordagem mais eficiente é manter uma única conexão HTTP ativa, reutilizando-a pelo maior tempo possível. Se a conexão for encerrada prematuramente porque uma imagem foi transferida por download, o navegador precisará criar uma nova conexão, o que pode ser muito lento em ambientes de baixa latência.
Uma solução alternativa para isso é usar a solicitação HTTP Range, que permite que os navegadores especifiquem um intervalo de bytes para buscar. Um navegador inteligente pode fazer uma solicitação HEAD para acessar o cabeçalho, processá-lo, decidir quanto da imagem é realmente necessário e, em seguida, fazer a busca. Infelizmente, o intervalo HTTP tem pouco suporte em servidores da Web, o que torna essa abordagem impraticável.
Por fim, uma limitação óbvia dessa abordagem é que você não pode escolher qual imagem carregar, apenas variar a fidelidade da mesma imagem. Como resultado, isso não aborda o caso de uso de direção de arte.
Usar o JavaScript para decidir qual imagem carregar
A primeira e mais óbvia abordagem para decidir qual imagem carregar é
usar JavaScript no cliente. Essa abordagem permite que você descubra
tudo sobre o user agent e faça a coisa certa. É possível
determinar a proporção de pixels do dispositivo com window.devicePixelRatio
, receber a largura
e a altura da tela e até mesmo fazer uma varredura de conexão de rede
com navigator.connection ou emitir uma solicitação falsa, como a
biblioteca foresight.js. Depois de coletar todas
essas informações, você pode decidir qual imagem carregar.
Há aproximadamente um milhão de bibliotecas JavaScript que usam essa técnica. Infelizmente, nenhum deles é particularmente notável.
Uma grande desvantagem é que você atrasa o carregamento de imagens até que o analisador de
antecipação seja concluído. Isso significa que as imagens nem mesmo começam
a ser transferidas até que o evento pageload
seja acionado. Saiba mais sobre isso no
artigo de Jason Grigsby.
Decidir qual imagem carregar no servidor
É possível adiar a decisão para o lado do servidor escrevendo manipuladores de solicitação personalizados para cada imagem que você serve. Esse manipulador verificaria o suporte da Retina com base no User-Agent (a única informação compartilhada com o servidor). Em seguida, com base em se a lógica do lado do servidor quer servir ativos HiDPI, carregue o ativo apropriado (nomeado de acordo com alguma convenção conhecida).
Infelizmente, o User-Agent não fornece informações suficientes
para decidir se um dispositivo precisa receber imagens de alta ou baixa
qualidade. E qualquer solução que use o User-Agent
para tomar decisões
de estilo precisa ser evitada.
Usar consultas de mídia CSS
Por serem declarativas, as consultas de mídia do CSS permitem que você declare sua intenção e
permitem que o navegador faça a coisa certa em seu nome. Além do uso mais
comum de consultas de mídia, que corresponde ao tamanho do dispositivo, você também
pode corresponder a devicePixelRatio
. A consulta de mídia associada é
"device-pixel-ratio" e tem variantes mínimas e máximas associadas, como
esperado.
Se você quiser carregar imagens de alta DPI e a proporção de pixels do dispositivo ultrapassar um limite, faça o seguinte:
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
Fica um pouco mais complicado com todos os prefixos de fornecedores misturados, principalmente devido às grandes diferenças de posicionamento dos prefixos "min" e "max":
@media only screen and (min--moz-device-pixel-ratio: 1.5),
(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),
(min-device-pixel-ratio: 1.5) {
#my-image {
background:url(high.png);
}
}
Com essa abordagem, você recupera os benefícios da análise antecipada, que foi perdida com a solução JavaScript. Você também ganha a flexibilidade de escolher os pontos de interrupção responsivos (por exemplo, é possível ter imagens de DPI baixa, média e alta), o que era perdido com a abordagem do lado do servidor.
Infelizmente, ele ainda é um pouco difícil de usar e leva a um CSS
com aparência estranha ou requer pré-processamento. Além disso, essa abordagem é restrita a
propriedades CSS. Portanto, não há como definir um <img src>
, e todas as imagens
precisam ser elementos com um plano de fundo. Por fim, ao depender apenas da
proporção de pixels do dispositivo, você pode acabar em situações em que o smartphone
de alta densidade de pixels acaba fazendo o download de um recurso de imagem enorme
em 2x enquanto está em uma
conexão EDGE. Essa não é a melhor experiência do usuário.
Como image-set()
é uma função CSS, ela não resolve o problema para
tags <img>
. Digite @srcset, que resolve esse problema.
A próxima seção aborda image-set
e srcset
em mais detalhes.
Recursos do navegador para suporte a DPI alto
A maneira como você aborda o suporte a DPI alto depende dos seus requisitos específicos. Todas as abordagens mencionadas têm desvantagens.
Agora que image-set
e srcset
têm suporte amplo, eles são as melhores
soluções. Há outras práticas recomendadas que podem nos aproximar
de navegadores mais antigos.
Qual é a diferença entre os dois? image-set()
é uma função
CSS, adequada para uso como um valor da propriedade CSS de plano de fundo.
srcset
é um atributo específico para elementos <img>
, com sintaxe semelhante.
Ambas as tags permitem especificar declarações de imagem, mas o atributo srcset
também permite configurar qual imagem carregar com base no tamanho
da viewport.
Práticas recomendadas para image-set
A sintaxe image-set()
usa uma ou mais declarações de imagem separadas por vírgulas,
que consistem em uma string de URL ou função url()
seguida pela resolução
adequada. Exemplo:
image-set(
url("image1.jpg") 1x,
url("image2.jpg") 2x
);
/* You can also include image-set without `url()` */
image-set(
"image1.jpg" 1x,
"image2.jpg" 2x
);
Isso informa ao navegador que há duas imagens para escolher. Uma imagem é otimizada para telas de 1x e a outra para telas de 2x. O navegador pode escolher qual carregar com base em vários fatores, que podem incluir até mesmo a velocidade da rede, se o navegador for inteligente o suficiente.
Além de carregar a imagem correta, o navegador a dimensiona adequadamente. Em outras palavras, o navegador assume que duas imagens são duas vezes maiores que as imagens 1x e, portanto, reduz a imagem 2x em um fator de 2, para que a imagem pareça ter o mesmo tamanho na página.
Em vez de especificar 1x, 1,5x ou Nx, você também pode especificar uma determinada densidade de pixels do dispositivo em DPI.
Se você estiver preocupado com navegadores mais antigos que não oferecem suporte à propriedade image-set
, adicione uma alternativa para garantir que uma imagem seja exibida. Exemplo:
/* Fallback support. */
background-image: url(icon1x.jpg);
background-image: image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
Esse código de exemplo carrega o recurso apropriado em navegadores que oferecem suporte a image-set e, caso contrário, usa o recurso 1x.
Neste ponto, você pode estar se perguntando por que não usar um polifil (ou seja,
criar um shim JavaScript para) image-set()
e encerrar o dia. Como
acontece, é bastante difícil implementar polyfills eficientes para funções
CSS. Para uma explicação detalhada, consulte esta discussão no estilo
www.
Srcset de imagem
Além das declarações que image-set
fornece,
o elemento srcset
também recebe valores de largura e altura que correspondem ao
tamanho da viewport, tentando exibir a versão mais relevante.
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
Este exemplo serve banner-phone.jpeg
para dispositivos com largura de janela de visualização abaixo de
640 px, banner-phone-HD.jpeg
para dispositivos de alta densidade de pixels com tela pequena,
banner-HD.jpeg
para dispositivos de alta densidade de pixels com telas maiores que 640 px e
banner.jpeg
para todos os outros.
Usar image-set para elementos de imagem
Pode ser tentador substituir os elementos img por <div>
s
com planos de fundo e usar a abordagem de conjunto de imagens. Isso funciona, com
precauções. A desvantagem é que a tag <img>
tem valor semântico
de longa duração. Na prática, isso é importante para a acessibilidade e
rastreadores da Web.
Você pode usar a propriedade CSS de conteúdo, que dimensiona automaticamente a imagem
com base em devicePixelRation
. Exemplo:
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
Polyfill srcset
Um recurso útil do srcset
é que ele vem com uma substituição natural.
No caso em que o atributo srcset não é implementado, todos os navegadores
sabem processar o atributo src. Além disso, como é apenas um atributo
HTML, é possível criar polyfills com
JavaScript.
Esse polyfill vem com testes de unidade para garantir que ele esteja o mais próximo possível da especificação. Além disso, há verificações em vigor que impedem que o polyfill execute qualquer código se o srcset for implementado de forma nativa.
Conclusão
A melhor solução para imagens de alta DPI é optar por SVGs e CSS. No entanto, essa não é sempre uma solução realista, especialmente para sites com muitas imagens.
As abordagens em JavaScript, CSS e soluções do lado do servidor têm pontos fortes
e fracos. A abordagem mais promissora é usar image-set
e srcset
.
Para resumir, minhas recomendações são as seguintes:
- Para imagens de plano de fundo, use image-set com as alternativas adequadas para navegadores que não oferecem suporte a ele.
- Para imagens de conteúdo, use um polyfill srcset ou use o uso de image-set como substituto (consulte acima).
- Para situações em que você está disposto a sacrificar a qualidade da imagem, use imagens com compressão 2x.