O elemento picture e os formatos de fallback
O picture permite servir o formato mais eficiente para cada navegador sem deixar ninguém sem imagem. É a peça-chave para usar AVIF hoje com total segurança.
Para que serve o picture
O <picture> envolve um <img> e adiciona uma lista de fontes alternativas. O navegador percorre os <source> em ordem e usa o primeiro que atender às condições (tipo de arquivo suportado e media query). Se nenhum servir, usa o <img>.
Ele tem dois usos principais:
- Troca de formato: servir AVIF ou WebP para quem os suporta e JPEG para o resto.
- Direção de arte: mostrar um recorte diferente conforme o tamanho da tela (por exemplo, um enquadramento vertical no celular).
Troca de formato
<picture>
<source type="image/avif" srcset="produto.avif">
<source type="image/webp" srcset="produto.webp">
<img src="produto.jpg" width="1200" height="1200" alt="Tênis de corrida azul visto de lado">
</picture>
Pontos importantes:
- O atributo
typeé o que permite ao navegador descartar uma fonte sem baixá-la. Sem ele, poderia baixar um arquivo que não sabe exibir. - A ordem vai do formato mais eficiente ao mais compatível.
- O
<img>final é obrigatório: é ele que é realmente exibido e que levaalt,width,height,loadingefetchpriority.
Um navegador que suporta AVIF vai baixar só produto.avif. Ele nunca baixa várias fontes para a mesma imagem.
Estilos e atributos: sempre no img
Um erro frequente é aplicar classes ou atributos ao <picture> ou aos <source>. Na maioria dos casos o <picture> não é renderizado como uma caixa própria; quem ocupa espaço é o <img>. Por isso:
- As classes CSS de tamanho,
object-fit, bordas etc. vão no<img>. alt,width,height,loading,decodingefetchpriorityvão no<img>.- Os
<source>levam apenastype,srcset,sizesemedia.
Combinar formatos e tamanhos
Cada <source> aceita srcset e sizes, então você pode oferecer várias larguras em cada formato:
<picture>
<source type="image/avif"
srcset="hero-960.avif 960w, hero-1920.avif 1920w"
sizes="100vw">
<source type="image/webp"
srcset="hero-960.webp 960w, hero-1920.webp 1920w"
sizes="100vw">
<img src="hero-1920.jpg"
srcset="hero-960.jpg 960w, hero-1920.jpg 1920w"
sizes="100vw"
width="1920" height="800" alt="…" fetchpriority="high">
</picture>
O ImageZap gera exatamente essa marcação: ative vários formatos e variantes responsivas, abra Código em qualquer imagem e copie o resultado. Para uma única imagem com o sizes já calculado, use o gerador de srcset.
Direção de arte com media
Se no celular você quer um recorte diferente, use media:
<picture>
<source media="(max-width: 640px)" srcset="banner-vertical.avif" type="image/avif">
<source media="(max-width: 640px)" srcset="banner-vertical.jpg">
<source srcset="banner-horizontal.avif" type="image/avif">
<img src="banner-horizontal.jpg" width="1600" height="600" alt="…">
</picture>
Lembre-se de que, se as proporções mudarem, os atributos width e height do <img> só descrevem a versão de desktop. Os navegadores modernos permitem colocar width e height também em cada <source> para reservar o espaço correto em cada caso.
E as imagens de fundo em CSS?
Para fundos, a função image-set() cumpre o mesmo papel:
.hero {
background-image: url("hero.jpg");
background-image: image-set(
url("hero.avif") type("image/avif"),
url("hero.webp") type("image/webp"),
url("hero.jpg") type("image/jpeg")
);
}
A primeira declaração funciona como fallback para navegadores que não entendem image-set() com type(). Lembre-se de que as imagens de fundo são descobertas tarde: se for a imagem LCP, adicione um <link rel="preload">.
Perguntas frequentes
O picture afeta o SEO?
Não negativamente. O Google indexa a imagem do <img> e também entende as fontes alternativas. O que conta é o alt do <img>.
Posso colocar JPEG XL no picture?
Sim, como primeira fonte. O Safari vai usá-lo e os demais navegadores vão passar para a próxima. Garanta que incluiu type="image/jxl".
Preciso de picture se só uso WebP?
Se o seu público usa navegadores modernos, um <img src="foto.webp"> basta. O picture é necessário quando você combina formatos ou faz direção de arte.
E o lazy loading?
Funciona igual: coloque loading="lazy" no <img> (exceto na imagem principal).