Carregamento lento de imagens

As imagens podem aparecer em uma página da Web por estarem inline no HTML como elementos <img> ou como imagens de plano de fundo CSS. Nesta postagem, você descobrirá como carregar lentamente os dois tipos de imagem.

Imagens inline

As candidatas de carregamento lento mais comuns são imagens como as usadas em elementos <img>. Com as imagens inline, temos três opções de carregamento lento, que podem ser usadas em conjunto para oferecer a melhor compatibilidade entre navegadores:

Como usar o carregamento lento no nível do navegador

O Chrome e o Firefox são compatíveis com carregamento lento com o atributo loading. Esse atributo pode ser adicionado a elementos <img> e <iframe>. Um valor de lazy instrui o navegador a carregar a imagem imediatamente se ela estiver na janela de visualização e a buscar outras imagens quando o usuário rolar a tela para perto delas.

Consulte o campo loading da tabela de compatibilidade de navegadores do MDN para detalhes sobre suporte a navegadores. Se o navegador não for compatível com o carregamento lento, o atributo será ignorado, e as imagens serão carregadas imediatamente, como de costume.

Para a maioria dos sites, adicionar esse atributo a imagens inline proporciona uma melhora de desempenho e evita que os usuários carreguem imagens que talvez não consigam acessar. Se você tiver um grande número de imagens e quiser garantir que os usuários de navegadores sem suporte a esse recurso tenham o benefício de carregamento lento, você precisará combinar isso com um dos métodos explicados a seguir.

Para saber mais, consulte Carregamento lento no nível do navegador para a Web.

Como usar o Intersection Observer

Para o carregamento lento de polyfill de elementos <img>, usamos o JavaScript para verificar se eles estão na janela de visualização. Se forem, os atributos src (e às vezes srcset) serão preenchidos com URLs para o conteúdo da imagem desejado.

Se você já escreveu um código de carregamento lento, sua tarefa pode ter sido concluída usando manipuladores de eventos como scroll ou resize. Embora essa abordagem seja a mais compatível com navegadores, os navegadores mais recentes oferecem uma maneira mais eficiente e eficiente de verificar a visibilidade do elemento usando a API Intersection Observer.

O Intersection Observer é mais fácil de usar e ler do que códigos que dependem de vários manipuladores de eventos, porque você só precisa registrar um observador para observar os elementos, em vez de escrever um código tedioso de detecção de visibilidade de elementos. Agora só falta decidir o que fazer quando um elemento estiver visível. Vamos supor esse padrão básico de marcação para os elementos <img> de carregamento lento:

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

Há três partes relevantes dessa marcação nas quais você deve se concentrar:

  1. O atributo class, que é usado para selecionar o elemento no JavaScript.
  2. O atributo src, que faz referência a uma imagem de marcador que vai aparecer quando a página for carregada pela primeira vez.
  3. Os atributos data-src e data-srcset, que são atributos de marcador que contêm o URL da imagem que você vai carregar quando o elemento estiver na janela de visualização.

Agora vamos ver como usar o Intersection Observer no JavaScript para carregar imagens lentamente usando esse padrão de marcação:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

No evento DOMContentLoaded do documento, esse script consulta o DOM de todos os elementos <img> com uma classe lazy. Se o Intersection Observer estiver disponível, crie um novo observador que execute um callback quando os elementos img.lazy entrarem na janela de visualização.

O Intersection Observer está disponível em todos os navegadores mais recentes. Portanto, usá-lo como um polyfill para loading="lazy" vai garantir que o carregamento lento esteja disponível para a maioria dos visitantes.

Imagens no CSS

Embora as tags <img> sejam a maneira mais comum de usar imagens em páginas da Web, as imagens também podem ser invocadas usando a propriedade CSS background-image (e outras propriedades). O carregamento lento no nível do navegador não se aplica a imagens de plano de fundo do CSS. Portanto, você precisa considerar outros métodos se tiver imagens de plano de fundo para o carregamento lento.

Ao contrário dos elementos <img>, que são carregados independentemente da visibilidade, o comportamento de carregamento de imagens no CSS é feito com mais especulação. Quando o documento e os modelos de objeto CSS e a árvore de renderização são criados, o navegador examina como o CSS é aplicado a um documento antes de solicitar recursos externos. Se o navegador determinou que uma regra CSS que envolve um recurso externo não se aplica ao documento como ele está sendo criado, o navegador não faz a solicitação.

Esse comportamento especulativo pode ser usado para adiar o carregamento de imagens no CSS, usando JavaScript para determinar quando um elemento está na janela de visualização e, depois, aplicando uma classe a esse elemento para aplicar o estilo à invocação de uma imagem de plano de fundo. Isso faz com que o download da imagem seja feito no momento necessário, e não no carregamento inicial. Por exemplo, vamos pegar um elemento que contenha uma imagem de plano de fundo de um grande herói:

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

Normalmente, o elemento div.lazy-background contém a imagem de plano de fundo principal invocada por algum CSS. No entanto, neste exemplo de carregamento lento, é possível isolar a propriedade background-image do elemento div.lazy-background usando uma classe visible adicionada ao elemento quando ele está na janela de visualização:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

Em seguida, use o JavaScript para verificar se o elemento está na janela de visualização (com o Intersection Observer) e adicione a classe visible ao elemento div.lazy-background, que carrega a imagem:

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

Efeitos na Maior exibição de conteúdo (LCP, na sigla em inglês)

O carregamento lento é uma ótima otimização que reduz o uso geral de dados e a contenção de rede durante a inicialização, adiando o carregamento de imagens para quando elas forem realmente necessárias. Isso pode melhorar o tempo de inicialização e reduzir o processamento na linha de execução principal, reduzindo o tempo necessário para a decodificação de imagens.

No entanto, o carregamento lento é uma técnica que pode afetar negativamente a Maior LCP de exibição de conteúdo do seu site, se você quiser usá-la. Evite o carregamento lento de imagens que estão na janela de visualização durante a inicialização.

Ao usar carregadores lentos baseados em JavaScript, evite o carregamento lento de imagens na janela de visualização, porque essas soluções geralmente usam um atributo data-src ou data-srcset como marcador de posição para os atributos src e srcset. O problema é que o carregamento dessas imagens atrasa porque o scanner de pré-carregamento do navegador não consegue encontrá-las durante a inicialização.

Mesmo o uso do carregamento lento no nível do navegador para uma imagem na janela de visualização pode não funcionar corretamente. Quando loading="lazy" é aplicado a uma imagem na janela de visualização, essa imagem é atrasada até que o navegador saiba com certeza que está na janela de visualização. Isso pode afetar a LCP da página.

Nunca faça o carregamento lento de imagens que aparecem na janela de visualização durante a inicialização. É um padrão que afetará negativamente a LCP do seu site e, portanto, a experiência do usuário. Se você precisar de uma imagem na inicialização, faça o carregamento lento o mais rápido possível nesse momento.

Bibliotecas de carregamento lento

Use o carregamento lento no nível do navegador sempre que possível, mas se isso não for possível, como um grupo significativo de usuários que ainda dependem de navegadores mais antigos, as seguintes bibliotecas podem ser usadas para o carregamento lento de imagens:

  • A Lazysizes é uma biblioteca de carregamento lento com recursos completos que faz o carregamento lento de imagens e iframes. O padrão usado é muito semelhante aos exemplos de código mostrados aqui, porque se vincula automaticamente a uma classe lazyload em elementos <img> e exige que você especifique URLs de imagem nos atributos data-src e/ou data-srcset, com conteúdo trocado por atributos src e/ou srcset, respectivamente. Ela usa o Intersection Observer, que você pode usar com polyfill, e pode ser estendido com vários plug-ins para fazer coisas como carregar vídeos lentamente. Saiba mais sobre o uso de Slowsizes.
  • vanilla-Slowload é uma opção leve para imagens, imagens de plano de fundo, vídeos, iframes e scripts. Ele aproveita o Intersection Observer, tem suporte a imagens responsivas e ativa o carregamento lento no nível do navegador.
  • O lozad.js é outra opção leve que usa apenas o Intersection Observer. Sendo assim, ele é de alto desempenho, mas precisará ser polido antes de ser usado em navegadores mais antigos.
  • Se você precisar de uma biblioteca de carregamento lento específica do React, considere react-Lazyload. Embora não use o Intersection Observer, ele fornece um método conhecido de carregamento lento de imagens para quem está acostumado a desenvolver aplicativos com o React.