Carregamento de imagens da web mais otimizado em 2021



Neste artigo, irei compartilhar 8 técnicas para otimizar o carregamento de imagens que reduzem a largura de banda da rede necessária e a carga do processador quando exibidas na tela. Aqui estão alguns exemplos de HTML com anotações para facilitar a sua reprodução. Algumas técnicas são conhecidas há muito tempo e outras surgiram há relativamente pouco tempo. Idealmente, seu mecanismo de publicação de documento da Web favorito (como um CMS, gerador de site estático ou estrutura de aplicativo da Web) deve fazer tudo isso imediatamente.



Coletivamente, as técnicas otimizam todos os elementos do Google Core Web Vitals por:





Para ver todas as técnicas em ação, dê uma olhada no código-fonte para carregar esta imagem:



https://www.industrialempathy.com/img/remote/ZiClJf.jpg
<img loading="lazy" decoding="async" style="background-size: cover; background-image: none;" src="/img/remote/ZiClJf.avif" alt="Sample image illustrating the techniques outlined in this post." width="4032" height="2268">

      
      







Técnicas de otimização



Layout responsivo



Essa técnica simples permite que a imagem ocupe o espaço horizontal disponível, mantendo a proporção da imagem. Em 2020, os navegadores aprenderam a reservar a quantidade correta de espaço vertical para uma imagem antes de carregar se o elemento img



contiver atributos width



e height



. Isso evita a mudança cumulativa do layout.



<style>
 img {
   max-width: 100%;
   height: auto;
 }
</style>
<!-- Providing width and height is more important than ever. -->
<img height="853" width="1280" … />

      
      





Renderização preguiçosa



A segunda técnica é mais complicada. O novo atributo CSS content-visibility: auto



diz ao navegador para não pensar em colocar a imagem até que esteja pronta. Essa abordagem tem várias vantagens, a principal delas é que até que o navegador receba uma imagem desfocada de espaço reservado ou a própria imagem, ele não a decodificará, economizando recursos do processador.



Não é mais necessário conter tamanho intrínseco



Uma versão anterior do artigo explicou como contain-intrinsic-size



evitar o efeito CLS ao usar content-visibility: auto



. Mas no Chromium 88 isso não é mais necessário no caso de imagens para as quais width



e height



. A partir de 27 de janeiro de 2021, content-visibility: auto



ainda não implementados em outros motores de navegador
, eles provavelmente seguirão o exemplo do Chromium. Então, sim, é muito mais fácil agora!



<style>
 /* This probably only makes sense for images within the main scrollable area of your page. */
 main img {
   /* Only render when in viewport */
   content-visibility: auto;
 }
</style>

      
      





AVIF



AVIF é o formato gráfico mais recente que recebeu suporte em navegadores. Agora é compatível com Chromium e por sinalização no Firefox. O Safari ainda não funciona com ele, mas como a Apple faz parte do grupo que desenvolveu o formato, este navegador também deverá suportar AVIF no futuro.



Este formato é notável por ser muito superior ao JPEG. E isso se compara favoravelmente com o formato WebP, cujas imagens nem sempre são menores que JPEG e que podem aumentar o consumo de recursos devido à falta de suporte para carregamento progressivo.



Para implementar uma extensão progressiva para AVIF, você pode usar picture



.



O elemento está realmente img



aninhado em picture



... Isso pode ser confuso, porque img



às vezes é chamado de solução alternativa para navegadores que não oferecem suporte picture



, mas na verdade esse elemento apenas ajuda na seleção src



e não tem seu próprio layout. O elemento img



será desenhado e você aplicará o estilo a ele.



Até recentemente, era muito difícil implementar imagens AVIF no lado do servidor, mas versões recentes de bibliotecas como o Sharp tornaram essa tarefa muito mais fácil.



<picture>
 <source
   sizes="(max-width: 608px) 100vw, 608px"
   srcset="
     /img/Z1s3TKV-1920w.avif 1920w,
     /img/Z1s3TKV-1280w.avif 1280w,
     /img/Z1s3TKV-640w.avif   640w,
     /img/Z1s3TKV-320w.avif   320w
   "
   type="image/avif"
 />
 <!-- snip lots of other stuff -->
 <img />
</picture>

      
      





Carregando o número correto de pixels



O código acima possui atributos srcset



e sizes



. Eles usam um seletor w



para informar ao navegador qual URL usar com base no número físico de pixels necessários para renderizar a imagem em um determinado dispositivo. Esse valor depende da largura da imagem, que é calculada com base no atributo sizes



(que é uma expressão da consulta de mídia).



Isso garante que o navegador sempre carregue a menor imagem possível, fornecendo a melhor qualidade em um determinado dispositivo. Como alternativa, ele pode selecionar a menor imagem se o usuário habilitou o modo de salvamento de dados.



Solução alternativa



Para navegadores que suportam apenas formatos de imagem mais antigos, você pode srcset



fornecer mais elementos brutos com a ajuda de:



<source
 sizes="(max-width: 608px) 100vw, 608px"
 srcset="
   /img/Z1s3TKV-1920w.webp 1920w,
   /img/Z1s3TKV-1280w.webp 1280w,
   /img/Z1s3TKV-640w.webp   640w,
   /img/Z1s3TKV-320w.webp   320w
 "
 type="image/webp"
/>
<source
 sizes="(max-width: 608px) 100vw, 608px"
 srcset="
   /img/Z1s3TKV-1920w.jpg 1920w,
   /img/Z1s3TKV-1280w.jpg 1280w,
   /img/Z1s3TKV-640w.jpg   640w,
   /img/Z1s3TKV-320w.jpg   320w
 "
 type="image/jpeg"
/>

      
      





Cache e URLs imutáveis



Incorpore no URL da imagem um hash do número de bytes que a imagem ocupa. No exemplo acima, eu fiz isso com Z1s3TKV



. Quando você altera a imagem, o URL também muda, o que significa que você pode aplicar o cache infinito de imagens. Os cabeçalhos de cache devem ser semelhantes cache-control: public,max-age=31536000,immutable



.



immutable



É um significado semanticamente correto cache-control



, mas tem pouco suporte a navegadores hoje (estou olhando para você, Chrome). max-age=31536000



- método de armazenamento em cache substituto ao longo do ano. public



é necessário para o seu CDN armazenar a imagem em cache e entregá-la da borda da rede. Mas essa abordagem só pode ser usada se não violar suas políticas de privacidade.



Carregamento lento



Ao adicionar loading=«lazy»



ao elemento, img



dizemos ao navegador para começar a buscar a imagem apenas quando ela estiver pronta para ser renderizada.



<img loading="lazy" … />

      
      





Descriptografia assíncrona



Ao adicionar decoding=«async»



ao elemento, img



permitimos que o navegador descriptografe a imagem fora do stream principal para que esse procedimento não interfira com o usuário. Não deve haver nenhuma falha perceptível nesta solução, exceto que nem sempre é aplicável por padrão em navegadores mais antigos.



<img decoding="async" … />

      
      





Esboço borrado



Um stub difuso é uma imagem embutida que dá ao usuário uma ideia de uma imagem completa que será carregada posteriormente, sem transferir dados pela rede.



https://www.industrialempathy.com/img/blurry.svg





Algumas notas de implementação:



  • O esboço é embutido como background-image



    imagens. Essa técnica permite eliminar o segundo elemento HTML, ocultando literalmente o stub quando a imagem principal é carregada, sem a necessidade de JavaScript.
  • O URI dos dados da imagem principal é agrupado no URI dos dados da imagem SVG. Isso é feito porque o desfoque é feito no nível SVG e não usando um filtro CSS. Ou seja, o desfoque é feito uma vez para cada imagem quando rasterizada por SVG, não para cada layout. Isso economiza recursos do processador.


<img
 style="
     …
     background-size: cover;
     background-image:
       url('data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http%3A//www.w3.org/2000/svg\'

xmlns%3Axlink=\'http%3A//www.w3.org/1999/xlink\' viewBox=\'0 0 1280 853\'%3E%3Cfilter id=\'b\' color-interpolation-filters=\'sRGB\'%3E%3CfeGaussianBlur stdDeviation=\'.5\'%3E%3C/feGaussianBlur%3E%3CfeComponentTransfer%3E%3CfeFuncA type=\'discrete\' tableValues=\'1 1\'%3E%3C/feFuncA%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter=\'url(%23b)\' x=\'0\' y=\'0\' height=\'100%25\' width=\'100%25\'
       xlink%3Ahref=\'data%3Aimage/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAIAAACepSOSAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAs0lEQVQI1wGoAFf/AImSoJSer5yjs52ktp2luJuluKOpuJefsoCNowB+kKaOm66grL+krsCnsMGrt8m1u8mzt8OVoLIAhJqzjZ2tnLLLnLHJp7fNmpyjqbPCqLrRjqO7AIeUn5ultaWtt56msaSnroZyY4mBgLq7wY6TmwCRfk2Pf1uzm2WulV+xmV6rmGyQfFm3nWSBcEIAfm46jX1FkH5Djn5AmodGo49MopBLlIRBfG8yj/dfjF5frTUAAAAASUVORK5CYII=\'%3E%3C/image%3E%3C/svg%3E');
   "
 …
/>

      
      





(Opcional) Otimização de JavaScript



Os navegadores podem ser forçados a rasterizar o esboço desfocado, mesmo se a imagem já estiver carregada. O problema pode ser resolvido removendo a rasterização na inicialização. Além disso, se sua imagem tiver áreas transparentes, essa otimização se torna obrigatória, caso contrário, um esboço aparecerá na imagem.



<sript>
 document.body.addEventListener(
   "load",
   (e) => {
     if (e.target.tagName != "IMG") {
       return;
     }
     // Remove the blurry placeholder.
     e.target.style.backgroundImage = "none";
   },
   /* capture */ true
 );
</sript>

      
      





Além disso



Uma ferramenta útil que implementa todas as otimizações descritas: eleventy-high-performance-blog



All Articles