Capítulo 33
Retina e srcset
6 min de leitura 1.143 palavras 2 gravuras
Esta é o capítulo 33 de 52 do volume Aprenda a Web. O projeto-fio é a Oficina Costeira, um coletivo fictício de design em João Pessoa. O exemplo está em exemplos/33-retina-srcset/. Em cada capítulo: leia, copie, mude uma coisa, preveja, recarregue e confira.
O que você vai aprender
- Entender densidade de pixels e por que a foto borra.
- Preferir CSS e SVG quando o desenho permite.
- Oferecer vários recortes com
srcsetesizes. - Trocar o enquadramento com
picture. - Preparar fundo de alta densidade.
- Limitar peso: nenhuma foto de estudo passa de 300 KB de brincadeira.
Tela nítida, arquivo maior
Muitos telefones desenham dois ou mais pixels do aparelho para cada pixel CSS. Uma foto de 400 px CSS precisa de cerca de 800 px de arquivo para não borrar. Isso se chama densidade. Não é “outra foto de outro assunto”: é a mesma cena, mais amostras.
Antes de duplicar JPG, pergunte: dá para fazer com CSS? Sombra, canto e degradê já são nítidos. A marca da Oficina Costeira em SVG também: o vetor não tem grade de pixels.
Foto da orla: raster. Aí entram srcset, picture ou um JPG único bem comprimido.
Erro comum: mandar um único JPG de 4000 px para “ficar retina”. A memória sobe. O telefone na rede lenta paga o preço. Ofereça tamanhos e deixe o navegador escolher.
Um JPG bem feito ainda vale
Meça no navegador a largura máxima em que a imagem aparece. Exporte o dobro. Comprima com qualidade baixa o bastante para o ruído não gritar — muitas vezes 30% a 50% num arquivo grande fica nítido quando reduzido.
Nenhuma imagem deste volume deve passar de cerca de 2500 px no lado maior nem de 300 KB sem motivo. A Oficina Costeira é exercício, não catálogo de agência.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Orla — Oficina Costeira</title>
<link rel="stylesheet" href="assets/stylesheets/main.css">
</head>
<body>
<main>
<h1>Recorte da orla</h1>
<img
src="assets/imagens/orla-800.jpg"
alt="Pôr do sol sobre o rio na Praia do Jacaré, em Cabedelo, com veleiro."
width="800"
height="1067">
</main>
</body>
</html>
width e height reservam espaço e evitam o pulo do layout. Copie. Adicione srcset no próximo capítulo.
srcset e sizes
srcset lista arquivos e a largura nativa em pixels (w). sizes diz quanto da viewport a imagem ocupa em cada faixa. O navegador combina densidade, largura e rede.
<img
src="assets/imagens/orla-800.jpg"
srcset="
assets/imagens/orla-1200.jpg 1200w,
assets/imagens/orla-800.jpg 800w,
assets/imagens/orla-400.jpg 400w"
sizes="(min-width: 60em) 40rem, 100vw"
alt="Pôr do sol sobre o rio na Praia do Jacaré, em Cabedelo, com veleiro."
width="800"
height="1067">
src aponta para o menor arquivo útil: navegador antigo ignora srcset. Comece a lista pelo maior w ou pelo menor; o que importa é o número bater com a largura real do arquivo.
100vw é a largura da viewport. 40rem é uma coluna. Escreva sizes como o CSS realmente se comporta, senão o navegador baixa o arquivo errado.
Mude sizes para 100vw só. Preveja um arquivo maior no desktop. Recarregue com o painel Rede aberto e cache desligado.

picture muda o recorte
srcset troca resolução da mesma composição. picture troca o recorte: no telefone um detalhe do cartaz; no desktop o cartaz inteiro.
<picture>
<source media="(min-width: 48rem)" srcset="assets/imagens/cartaz-largo.jpg">
<img
src="assets/imagens/cartaz-estreito.jpg"
alt="Cartaz fictício: Oficina Costeira, encontro em Tambaú, exemplo sem inscrições."
width="800"
height="1000">
</picture>
O primeiro source que casar vence. Coloque o mais largo no topo se usar min-width. O img final é obrigatório: é o recorte pequeno e o plano B.
Densidade dentro de um source:
<source
media="(min-width: 48rem)"
srcset="assets/imagens/cartaz-largo.jpg 1x, assets/imagens/cartaz-largo-2x.jpg 2x">
O alt continua no img, uma vez só. Os recortes contam a mesma história.
Erro comum: esquecer o img dentro de picture. Nada aparece em navegador antigo, e o validador reclama.
Fundo em alta densidade
CSS não tem srcset no mesmo formato. Use image-set ou uma media query de resolução.
.selo {
width: 3rem;
height: 3rem;
background-image: image-set(
url("../imagens/selo.png") 1x,
url("../imagens/selo-2x.png") 2x
);
background-size: 3rem 3rem;
}
O arquivo @2x tem o dobro dos pixels. background-size mantém o tamanho CSS. Sem isso, a imagem desenha em 6 rem e estoura o selo.
Conferir de verdade
Sirva imagens-responsivas.html do exemplo em 127.0.0.1. Desligue o cache. Estreite a janela e recarregue: o pedido deve ser o arquivo estreito. Alargue e recarregue. No aparelho de alta densidade, espere o 2x ou o w maior.
SVG da marca não precisa dessa dança. Foto da orla precisa. Não publique. Não use CDN paga como único caminho: os arquivos moram na pasta do exemplo.
sizes="100vw" mente se a foto ocupa só metade da home. O navegador baixa um arquivo de viewport inteira. Meça a coluna no inspetor. Escreva o sizes com essa medida: 40rem, 50vw, (min-width: 48rem) 20rem.
Descritor x (1x, 2x) fala densidade, não largura. Use w quando a mesma foto muda de coluna. Use x em ícone de tamanho fixo.
Copie o img com srcset. Apague sizes. Preveja um palpite ruim do navegador. Recarregue. Devolva o sizes.

Conferir nomes e peso
orla-400.jpg, orla-800.jpg e orla-1200.jpg deixam o srcset legível. foto2-nova.jpg não diz a largura. O número no nome deve bater com o descritor w.
Abra cada arquivo nas propriedades do Explorador. Anote a largura em pixels. Escreva o srcset com esses números, não com palpite.
Se os três arquivos tiverem o mesmo peso, a compressão falhou no maior. O arquivo de 1200 px pode ter qualidade menor e ainda assim parecer nítido quando reduzido — é o JPG “compressivo” da origem, reescrito aqui: dobre a largura, baixe a qualidade, deixe o navegador encolher.
Não sirva WebP como único formato neste volume. src em JPG cobre o plano B. type="image/webp" em source dentro de picture é passo extra, não obrigatório.
Mude o descritor 1200w para 800w de propósito. Preveja escolha errada. Recarregue o Rede. Corrija o número.
Dois arquivos iguais com nomes diferentes não criam retina. O de 2x precisa ter o dobro dos pixels. Abra as propriedades e compare 800×450 com 1600×900.
Se o painel Rede mostrar os três JPG de uma vez, o srcset pode estar malformado (vírgula faltando, quebra no meio de um URL). Escreva um candidato por linha, vírgula no fim da linha, como no exemplo do capítulo 3.
src continua obrigatório. Sem ele, navegador antigo não mostra foto nenhuma. O menor JPG é o plano B e também o palpite inicial de quem ainda não leu srcset.
Atividades
- Qual atributo lista as larguras nativas dos arquivos candidatos?
- Para que serve
sizes? - Quando usar
pictureem vez de sósrcsetnoimg? - Por que o
imginterno dopictureé obrigatório? - O que
background-sizefaz num ícone2x? - Qual o risco de escrever
sizes="100vw"numa foto que só ocupa metade da home?
Respostas comentadas
srcsetcom descritoresw(ouxpara densidade).- Informar ao navegador a largura de exibição em cada faixa, para ele não baixar um arquivo maior do que a coluna.
- Quando o recorte muda (art direction), não só a resolução da mesma foto.
- Compatibilidade e o recorte padrão. Sem
img, não há imagem nemalt. - Desenha o arquivo grande no tamanho CSS do ícone, mantendo nitidez sem estourar o layout.
- O navegador pode baixar um arquivo da largura da viewport, mais pesado do que a coluna precisa.
Referências
O arquivo completo
Referência do exemplo 33-retina-srcset, reproduzida aqui para que você possa conferir sem sair da página.
imagens-responsivas.html
<!doctype html><html lang="pt-BR"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Imagens responsivas — Oficina Costeira</title><link rel="stylesheet" href="assets/stylesheets/main.css"><a class="skip" href="#conteudo">Pular para o conteúdo</a><header class="site-header"><a href="index.html">Oficina Costeira</a></header><main id="conteudo" tabindex="-1" class="wrap"><h1>Conferir srcset e picture</h1><p>Altere uma largura, preveja o arquivo escolhido e confira no painel Rede com o cache desligado.</p><figure><img src="assets/imagens/orla-800.jpg" srcset="assets/imagens/orla-400.jpg 400w, assets/imagens/orla-800.jpg 800w, assets/imagens/orla-1200.jpg 1200w" sizes="(min-width:60em) 40rem,100vw" width="800" height="1067" alt="Pôr do sol sobre o rio na Praia do Jacaré, em Cabedelo, com veleiro e vegetação na margem."><figcaption>Fotografia real de Papel BR (domínio público); coletivo e encontros fictícios.</figcaption></figure><h2>Recortes do mesmo cartaz</h2><picture><source media="(min-width:48rem)" srcset="assets/imagens/cartaz-largo.jpg 1x, assets/imagens/cartaz-largo-2x.jpg 2x"><img src="assets/imagens/cartaz-estreito.jpg" width="800" height="1000" alt="Cartaz fictício: Oficina Costeira, encontro em Tambaú, exemplo sem inscrições."></picture><p><a href="index.html">Voltar ao exemplo</a></p></main><footer>Conteúdo fictício de estudo.</footer></html>
assets/javascript/simulacao.js
const form=document.querySelector("#simulacao");if(form){form.querySelector("button[type=submit]").disabled=false;form.addEventListener("submit",event=>{event.preventDefault();document.querySelector("#retorno").textContent="Simulação concluída. Nada foi enviado ou guardado.";});}