# Imagens responsivas com srcset e sizes

> Srcset e sizes: imagens responsivas baseadas em viewport HTML. Controle inteligente de resolução e densidade de pixels para performance otimizada!

URL: https://dpw.dev/css/imagens-responsivas-srcset-sizes/  
Publicado em: 2015-06-25  
Categoria: css  
Tags: basico-da-web, performance, planejamento, web-design-responsivo  
Autor: Tárcio Zemel

Um assunto que está evoluindo bastante em **web design responsivo** é como lidar com imagens responsivas de maneira apropriada e eficiente -- [assunto inclusive abordado anteriormente aqui no blog](/design/imagens-responsivas-srcset-picture/ "Imagens em web design responsivo: atributo srcset e elemento picture"). Neste artigo, conheça mais sobre **srcset** e **sizes**, seus novos amigos na hora de planejar e implementar imagens responsivas em web design responsivo.

> Artigo baseado em [Srcset and sizes](https://ericportis.com/posts/2014/srcset-sizes/).

## O que há de errado com Media Queries?

Digamos que você está fazendo um site entre [23 de fevereiro de 1993](http://1997.webhistory.org/www.lists/www-talk.1993q1/0182.html) e [25 de maio de 2010](http://alistapart.com/article/responsive-web-design/). Trabalhar com imagens é simples:

1. Olhe para seu layout de largura fixa
2. Meça _exatamente_ quantos pixels da tela de seus visitantes você vai _invariavelmente_ preencher com a imagem
3. Abra o Photoshop
4. Salve "para a web" aquela imagem, naquele exato tamanho
5. Crie sua tag `img`
6. Sirva-se de uma boa cerveja (ou talvez abra uma lata de ervilhas frescas) para comemorar mais um trabalho bem feito!

![Imagens responsivas com srcset e sizes: medindo o buraco](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-measuring-hole-1024x690.webp)

![Imagens responsivas com srcset e sizes: medindo a 'caixa'](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-measuring-image-1024x694.webp)

![Imagens responsivas com srcset e sizes: martelando](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-hammering-1024x683.webp)

![Imagens responsivas com srcset e sizes: ervilhas!](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-yay-peas-1014x1024.webp)

Embora alguns sábios profetas tenham, ocasionalmente, [falado uma ou outra verdade sobre os problemas inerentes a esta maneira de proceder](http://alistapart.com/article/dao/), a verdade é que esta tem sido a abordagem padrão de web designers por 20 anos.

Mas estes são outros tempos.

Alguns anos atrás, Ethan Marcotte publicou um artigo; 13 dias depois, Steve Jobs anunciou [um smartphone](http://en.wikipedia.org/wiki/IPhone_4); de repente, imagens "[fluidas](http://unstoppablerobotninja.com/entry/fluid-images)" e "[Retina](http://en.wikipedia.org/wiki/Retina_Display)" se tornaram "coisas" e; depois disso, [tem havido muito ranger de dentes](https://whatwg.org/mailing-list).

O primeiro instinto quando é preciso implementar imagens fluidas/responsivas é se valer da mesma ferramenta usada para layouts responsivos: **media queries**!

![Imagens responsivas com srcset e sizes: media queries](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-media-queries-1024x682.webp)

Navegadores não conseguem saber tudo sobre um website que eles ainda sequer carregaram, mas têm algumas informações sobre o ambiente em que estão inseridos: o tamanho de viewport, a resolução de tela etc. A ideia de media queries é: deixar desenvolvedores web fazer coisas específicas em ambientes específicos -- se a viewport é maior que mil pixels, mostre a barra lateral à esquerda; senão, mostre à direita; do contrário, empurre para baixo de todo o conteúdo.

Fácil como comer ervilhas!

![Imagens responsivas com srcset e sizes: comendo ervilhas](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-easypeas-1024x682.webp)

Infelizmente, quando se trata de imagens responsivas, em muitos casos, na prática, usar media queries pode ser [desagradavelmente terrível](http://www.xanthir.com/b4Su0).

![Imagens responsivas com srcset e sizes: comendo ervilhas](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-gulp-1024x682.webp)

Imagens responsivas baseadas em media queries não são tão eficientes porque a maioria dos web designers/desenvolvedores altera o layout de uma web page se baseando apenas em 1 variável -- largura da viewport --, quando, para lidar efetivamente com imagens responsivas, é preciso trabalhar com 3 variáveis:

1. Tamanho renderizado (em CSS pixels) da imagem no layout
2. Densidade de tela
3. Dimensão da gama de imagens de vários tamanhos à disposição

Uma vez que se saiba essas 3 coisas, a solução é simples: dado um conjunto de fontes, escolha a menor delas, cujas dimensões são ainda maiores do que o **tamanho renderizado x densidade tela**.

> Surpreendentemente, quando o navegador começa a carregar imagens, ele ainda não sabe qual é o tamanho renderizado!

Mas, infelizmente, tamanho renderizado é algo difícil de definir: desenvolvedores simplesmente não conseguimos saber qual é de antemão! Dentro de um layout responsivo, o tamanho renderizado de uma imagem pode ser qualquer um! E, surpreendentemente, quando o navegador começa a carregar imagens, ele ainda não sabe qual é o tamanho renderizado -- o tamanho renderizado depende do CSS em ação, que browsers geralmente interpretam (_parse_) depois de já terem começado a carregar imagens.

Felizmente (aparentemente), ao usar media queries nos arquivos-fonte é possível quebrar o problema em 2 partes menores:

- Dimensões da viewport
- Qual será o tamanho da imagem em relação à viewport

Exigindo aos desenvolvedores especificar somente o tamanho da viewport e densidade de tela, depois de ter completado muitos cálculos difíceis envolvendo todo o resto.

Mas que tipo de cálculos? Vamos a exemplos.

![Imagens responsivas com srcset e sizes: calculando](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-study-up-1024x682.webp)

Na verdade, a razão de ser desse exemplo é mostrar que o processo de cálculo de media queries é tedioso e propenso a erros. Então, se você está 100% convencido de que tudo o que se está dizendo sobre o assunto até agora é verdade, [pule para as explicações seguintes](#srcset-plus-sizes).

Digamos que se tenha 3 versões de uma imagem:

- `large.jpg` (1024 x 768)
- `medium.jpg` (640 x 480)
- `small.jpg` (320 x 240)

E é preciso escolher uma e carregá-la dentro em uma grid flexível -- uma grid que começa com uma coluna única, mas muda para mais colunas em viewports maiores, como [neste exemplo](https://ericportis.com/assets/2014-03-24-srcset-sizes/wolves/). Levando em consideração, também, que se quer suportar `1x` e `2x` para `device-pixel-ratio`.

Neste cenário, como organizar e codificar as media queries? Comecemos do topo.

`large.jpg` deve ser carregado somente quando absolutamente necessário -- quando `small.jpg` e `medium.jpg` forem pequenos demais. Mais precisamente, apenas se deve carregar `large.jpg` quando:

```
largura renderizada × densidade de tela > largura do próximo-menor-arquivo
```

No exemplo, largura renderizada é somente uma porcentagem da largura de viewport. Assim:

```
largura renderizada = largura da imagem relativa à viewport × largura de viewport
```

O próximo menor arquivo é `medium.jpg`, então:

```
largura do próximo-menor-arquivo = 640px
```

Colocando tudo junto:

```
largura da imagem relativa à viewport × largura de viewport × densidade de tela > 640px
```

Em que é possível ser reorganizado em termos de largura de viewport:

```
largura de viewport > 640px ÷ (largura da imagem relativa à viewport × densidade de tela)
```

Para fazer as media queries, resolvemos para a largura de viewport para cada valor possível de largura da imagem em relação à viewport e densidade tela.

largura da imagem em relação à viewport pode ter 1 de 2 valores: `100[vw](http://www.w3.org/TR/css3-values/#viewport-relative-lengths)` antes de bater no breakpoint (36em) e `33.3vw` depois disso.

Para densidade tela é possível fazer muita coisa, mas, para o exemplo, digamos que só se precise de suporte para `device-pixel-ratio` de `1x` e `2x`.

2 largura da imagem em relação à viewport possíveis x 2 densidade de tela = 4 cenários que precisam ser levados em consideração. Vejamos um a um.

### 1x, antes do breakpoint

Devido ao fato de o breakpoint ser em 36em, por definição se sabe que:

```
largura de viewport < 36em
```

Juntando largura da imagem em relação à viewport = 100vw e densidade de tela = 1x:

```
largura de viewport > 640px ÷ (100vw × 1x) = 640px = 40em
```

Quando se combina os 2, obtém-se algo impossível:

```
36em > largura de viewport > 40em
```

Então, podemos descartar este cenário, quer dizer, nunca será preciso usar `large.jpg` em `1x` com o layout de coluna única.

### 2x, antes do breakpoint

De novo:

```
largura de viewport < 36em
```

Mas agora usando 2x:

```
largura de viewport > 640px ÷ (100vw × 2x) = 320px = 20em
```

Combinando os 2:

```
 36em > largura de viewport > 20em
```

Então, carrega-se `large.jpg` em telas `2x` quando a viewport estiver nesta faixa.

### 1x, depois do breakpoint

Agora maior que a largura do breakpoint:

```
largura de viewport > 36em
```

Tendo em foco o layout com 3 colunas em telas 1x:

```
largura de viewport > 640px ÷ (33.3vw × 1x) = 1920px = 120em
```

A viewport sempre será mais larga que 36em quando for maior que 120em, então é possível ignorar esses 36em. Queremos carregar `large.jpg` em telas `1x` quando:

```
largura de viewport > 120em
```

### 2x, depois do breakpoint

```
largura de viewport > 36em
```

E...

```
largura de viewport > 640px ÷ ( 33.3vw × 2x ) = 960px = 60em
```

Então, em telas de 2x, carregar `large.jpg` quando:

```
largura de viewport > 60em
```

Colocando tudo junto numa media query:

```
    ( (min-device-pixel-ratio: 1.5) and (min-width: 20.001em) and (max-width: 35.999em) ) or
    ( (max-device-pixel-ratio: 1.5) and (min-width: 120.001em) ) or
    ( (min-device-pixel-ratio: 1.5) and (min-width: 60.001em) )

```

Como exercício, faça estes mesmos cálculos para `medium.jpg`. ;-)

Usando a proposta original de `<picture>` para marcar a imagem:

```

```

Uma dor de cabeça!

E uma pilha de marcação de `device-pixel-ratio` não suportados por 2, ou sob um, e imperfeitamente suporta aqueles no meio. Se é preciso estender o suporte a `device-pixel-ratio`, o número de cenários a serem considerados aumenta vertiginosamente!

E a pior parte sobre essa marcação é que, se qualquer uma das variáveis subjacentes for alterada -- o tamanho das imagens, resoluções dos dispositivos que precisam ser suportados ou qualquer aspecto do nosso layout que afeta o tamanho das imagens --, é preciso refazer toda a matemática novamente...

![Imagens responsivas com srcset e sizes: chamando o Raul](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-barf-1024x682.webp)

## srcset + sizes: ao resgate de imagens responsivas

Então, parece que media queries não são soluções mágicas para todos os problemas com imagens responsivas... E agora?

Voltando à lista de variáveis fundamentais de imagens responsivas, dessa vez pensando sobre _quando_ elas variam e _quem sabe o quê_, temos:

| Variável | Conhecido pelo autor quando o código é escrito? | Conhecido pelo browser quando a página é carregada? |
| --- | --- | --- |
| Dimensões da viewport | não | sim |
| Tamanho da imagem relativo à viewport | sim | não |
| Densidade de tela | não | sim |
| Dimensões do arquivo | sim | não |

Perceba que sempre que há um "sim" em uma coluna, há um "não" na outra: o autor e o navegador têm _informações complementares direrentes_!

Como melhorar essa situação?

Media queries são como um conjunto de planos de contingência. "Veja", dizemos para o navegador, "Eu não sei o quão grande essa viewport será, mas se for desse tamanho, use este ficheiro; se for maior, use este. Além disso, use este outro caso seja uma tela com densidade de pixels maior, mas não se o layout estiver com 3 colunas"... Na verdade, o que se está fazendo é rotular arquivos dentro de uma gama de possibilidades, sempre levando em conta coisas que o navegador vai saber, mas que nós, desenvolvedores web, ao escrever o código, não sabemos.

E, como já foi visto, na prática isso se transforma em um grande volume de trabalho... Mas e se invertêssemos isso?

E se, ao invés de fornecer ao browser diversos planos de contingência, simplesmente _informar as coisas que ele não sabe_? Isto é: como a imagem será dimensionada em relação à viewport e a dimensão dos arquivos de imagem. Nós sabemos essas coisas. Se fosse possível compartilhar esse conhecimento com o navegador, ele não teria tudo o que necessário para escolher uma fonte? Teria!

De fato, isso é justamente o que o atributo `sizes` e o descritor `w` de `srcset` fazem, segundo [a última especificação de `<picture>`](http://picture.responsiveimages.org/). Com isso, nossa tabela fica assim:

| Variável | Conhecido pelo autor quando o código é escrito? | Conhecido pelo browser quando a página é carregada? |
| --- | --- | --- |
| Dimensões da viewport | não | sim |
| Tamanho da imagem relativo à viewport | sim | não sim! via `sizes`! |
| Densidade de tela | não | sim |
| Dimensões do arquivo | sim | não sim! via `srcset`! |

![Imagens responsivas com srcset e sizes: arco-íris](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-rainbow-1024x682.webp)

Antes de continuarmos, vamos deixar 3 coisas claras.

Primeiro de tudo, tudo o que se está tratando aqui ainda não possui suporte oficial por todos os principais navegadores. Então, cautela.

Segundo: era uma vez uma proposta para imagens responsivas chamada [`srcset`](http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2012-May/035855.html). A proposta mais nova que está sendo tratada aqui tem o atributo que _também_ se chama `srcset`. Ambos, o antigo e o novo `srcset`, usam o `w` para coisas completamente diferentes! O antigo `w` era uma maneira simplificada de se escrever media queries: a largura descrita era a _largura da viewport_; o novo `w` descreve a _largura do arquivo_.

O novo `w` será tratado a seguir, mas, antes, você só precisa olhar por um segundo para um destes apagadores de memória estilo MIB e esquecer tudo o que você sabia sobre `srcset` e `w`. Olhe aqui por um instante...

![Imagens responsivas com srcset e sizes: MIB](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-mib-1024x682.webp)

Tudo certo? Muito bom!

Terceiro: a nova especificação de `<picture>` continua permitindo a alterar os arquivos usados com media queries e usar descritores de resolução às URLs. Se você está fazendo [direção de arte](http://usecases.responsiveimages.org/#art-direction) ou [alternância de resolução de tamanho fixo](http://usecases.responsiveimages.org/#device-pixel-ratio-based-selection), _você deve usar essas features_. Mas se você quer que suas imagens simplesmente se alarguem e se contraiam, eis uma nova ferramenta à disposição.

Isto posto, voltemos ao exemplo, dessa vez usando `<srcset>` e `<sizes>`. Recapitulando, há 3 versões de imagem:

- `large.jpg` (1024 x 768)
- `medium.jpg` (640 x 480)
- `small.jpg` (320 x 240)

Além de um breakpoint em 36em que troca o grid de 1 para 3 colunas.

Eis a marcação:

```

```

Você deve ter percebido que essa marcação vem da [especificação de "picture"](http://picture.responsiveimages.org/), embora não haja nenhum elemento `<picture>` no exemplo. Os atributos `<srcset>` e `<sizes>` serão implementados em `<img>`, também e, para casos em que não é preciso direção de arte / alternância de tipos como este, é possível -- e recomendado -- usar uma instância única de nossa velha amiga `<img>` para fazer a marcação das imagens responsivas.

A mesma boa e velha `<img>` com novos atributos. Analisemos um a um.

```
src="small.webp"

```

Nenhuma novidade aqui. É um fallback `src`, tal como sempre foi, que será interpretado por qualquer navegador que não entenda `<srcset>` e `<sizes>`. Próximo!

```
srcset="large.jpg 1024w,
        medium.jpg 640w,
        small.jpg 320w"

```

Este é auto explicativo, também. `srcset` pega uma lista de URLs separados por vírgula para as versões disponíveis da imagem; cada largura de imagem é especificada usando o descritor `w`. Então, se você salvar uma imagem de 1024x769, coloque `1024w` na marcação de `srcset`. Fácil.

![Imagens responsivas com srcset e sizes: declarativo](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-declarative-1024x682.webp)

Você deve ter notado que apenas a largura é informada. Por que não a altura, também? Imagens, em web design responsivo, são restringidas pela largura: suas larguras são explicitamente especificadas pelo CSS, mas suas alturas, não. A vasta maioria das imagens responsivas por aí são restringidas pela largura, também, então a especificação mantém as coisas simples ao lidar somente com larguras.

Olhando para o futuro, há algumas razões pelas quais o descritor `h` poderia ser usado -- mas ainda não.

E, novamente, saiba que, enquanto você pode usar descritores de resolução como `1x` e `2x` _ao invés_ de `w`, `1x`/`2x` _e_ `w` não se misturam! Não use ambos no mesmo `srcset`. Sério.

![Imagens responsivas com srcset e sizes: relâmpago](/images/blog/imagens-responsivas-srcset-sizes/imagens-responsivas-srcset-sizes-lightning-1024x682.webp)

O último pedacinho de informação que o browser precisa para escolher uma fonte é uma ideia de quão larga a imagem será quando for renderizada no layout. Para isso, usa-se `sizes`. No exemplo:

```typescript
sizes="(min-width: 36em) 33.3vw,
       100vw"

```

O formato aqui é:

```
sizes="[media query] [comprimento], [media query] [comprimento] etc"

```

Media queries ficam emparelhadas com comprimentos. O navegador passa por cada media query até encontrar um que sirva e usa seu comprimento correspondente como a última peça do quebra-cabeças: a largura da imagem renderizada em relação à viewport.

"Mas o que é isso?", você pode estar se perguntando. "Media queries? Não havia sido informado que não eram ideais para fazer isso?"

O que foi informado é que as media queries, por si só, não eram um mecanismo ideal para realizar essa escolha de fonte do arquivo. Não é isso o que essas queries estão fazendo; elas estão simplesmente deixando o browser encontrar uma maneira mais eficiente de fazer essa escolha.

> Acabaram-se as adivinhações sobre quais resoluções devem ou não serem suportadas.

Lembre-se de como as várias queries no primeiro exemplo não tinham nada a ver com o breakpoint de layout da página (que estava em 36em)? Quer dizer, 60em, 20em, 10em -- eles estavam em todo lugar! O breakpoint em `sizes` deve espelhar exatamente os breakpoints da página. O comprimento de cada um deles especifica a largura da imagem no layout quando essa media query entra em ação.

Então o navegador, tendo toda a informação necessária, faz o mesmo tipo de cálculo maçante, cansativo e sujeito a erro humano que foi mostrado anteriormente.

E se lembra como o exemplo de media query apenas cobria as densidade `1x` e `2x`? Essa marcação funciona com _qualquer_ `device-pixel-ratio`! Acabaram-se as adivinhações sobre quais resoluções devem ou não serem suportadas. Quando um smartwatch de `4.8625x` for lançado, `src` e `sizes` já darão conta do recado!

Além disso, essa solução dá aos navegadores algum "espaço de manobra". Uma media query vinculada a uma fonte pode ser verdadeira (true) ou falsa (false); se verdadeira, o navegador _deve_ carregar a fonte associada. `sizes` e `src` não são tão rígidos: a especificação permite que os navegadores, opcionalmente, carreguem arquivos menores quando a largura de banda é lenta ou cara.

"Bem, tudo isso é maravilhoso", você pode estar conversando consigo mesmo neste momento, agora que está começando a entender os benefícios de uma **abordagem declarativa** em detrimento a uma condicional. "Mas espere... O que é um 'comprimento'?"

[Um "comprimento" pode ser muitas coisas](http://www.w3.org/TR/css3-values/#lengths). Um comprimento pode ser absoluto (ex.: `99px`, `16em`) ou relativo (`33.3vw`). Você notará que, diferentemente do exemplo, existe um monte de layouts que combinam unidades absolutas e relativas. E é neste ponto que a [surpreendentemente bem suportada](http://caniuse.com/calc) [função `calc()`](http://dev.w3.org/csswg/css-values/#calc-notation) entra em ação.

Vamos supor que [foi adicionada uma barra lateral de 12em ao layout de 3 colunas](https://ericportis.com/assets/2014-03-24-srcset-sizes/wolves/wolfroll.html). Isso acarretaria na necessidade de tal ajuste:

```typescript
sizes="(min-width: 36em) calc(.333 * (100vw - 12em)),
       100vw"

```

Feito!

Se está prestando bastante atenção, você deve estar se perguntando nesse momento: "Mas o que diabos é esse '100vw' sozinho? Você se esqueceu da media query?".

Na especificação, um comprimento sem uma media query correspondente é um "comprimento padrão". Isso significa que, por exemplo, uma imagem gigante de um banner de largura total poderia ser marcado dessa maneira no seu código:

```

```

## Conclusão sobre imagens responsivas com srcset e sizes

**Web design responsivo** e **imagens responsivas** já são assuntos corriqueiros para desenvolvedores web. Não raramente nossa vontade de desenvolvedores aparece com mais rapidez com que as tecnologias são criadas, desenvolvidas e suportadas nos principais navegadores.

Imagens responsivas com `srcset` e `sizes` já são uma realidade; e melhor, uma realidade com fallback para navegadores que não suportam as características mais atuais de web design responsivo.

Esteja na vanguarda!

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
