Pular para o conteúdo
murad.guide

A Web Aberta

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

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.

Resumo dos conceitos: srcset, sizes, 2x

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.

Resumo dos conceitos: 2x, sizes, srcset

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

  1. Qual atributo lista as larguras nativas dos arquivos candidatos?
  2. Para que serve sizes?
  3. Quando usar picture em vez de só srcset no img?
  4. Por que o img interno do picture é obrigatório?
  5. O que background-size faz num ícone 2x?
  6. Qual o risco de escrever sizes="100vw" numa foto que só ocupa metade da home?

Respostas comentadas

  1. srcset com descritores w (ou x para densidade).
  2. Informar ao navegador a largura de exibição em cada faixa, para ele não baixar um arquivo maior do que a coluna.
  3. Quando o recorte muda (art direction), não só a resolução da mesma foto.
  4. Compatibilidade e o recorte padrão. Sem img, não há imagem nem alt.
  5. Desenha o arquivo grande no tamanho CSS do ícone, mantendo nitidez sem estourar o layout.
  6. 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.";});}