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 fazer o carregamento lento desses dois tipos de imagem.

Imagens inline

As candidatas mais comuns para o carregamento lento são imagens usadas em elementos <img>. Com imagens inline, temos três opções de carregamento lento que podem ser usadas em combinação 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 o 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 perto delas.

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

Para a maioria dos sites, adicionar esse atributo a imagens inline aumenta a performance e ajuda os usuários a carregar imagens que talvez nem nunca rolem. Se você tiver um grande número de imagens e quiser garantir que os usuários de navegadores sem suporte ao carregamento lento recebam benefícios, será necessário combinar essa opção 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 usar o polyfill no carregamento lento 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 desejada.

Se você já escreveu um código de carregamento lento antes, talvez tenha realizado sua tarefa usando manipuladores de eventos, como scroll ou resize. Embora essa abordagem seja a mais compatível com todos os navegadores, os navegadores modernos oferecem uma maneira mais eficiente e de desempenho de verificar a visibilidade do elemento usando a API Intersection Observer.

O Intersection Observer é mais fácil de usar e ler do que o código que depende 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. Tudo o que resta a fazer é decidir o que fazer quando um elemento estiver visível. Vamos supor este padrão básico de marcação para seus 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 em JavaScript.
  2. O atributo src, que faz referência a uma imagem de marcador que aparece quando a página é carregada pela primeira vez.
  3. Os atributos data-src e data-srcset, que são atributos de marcador de posição que contêm o URL da imagem que você vai carregar quando o elemento estiver na janela de visualização.

Agora vamos conferir como usar o Intersection Observer no JavaScript para fazer o carregamento lento de imagens com 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 modernos. Portanto, usá-lo como um polyfill para loading="lazy" vai garantir que o carregamento lento esteja disponível para a maioria dos visitantes.

Imagens em CSS

As tags <img> são a maneira mais comum de usar imagens em páginas da Web, mas elas também podem ser invocadas por meio da propriedade CSS background-image (e outras propriedades). O carregamento lento no navegador não se aplica a imagens de plano de fundo CSS. Portanto, você precisa considerar outros métodos se tiver imagens de plano de fundo para 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 os modelos de objeto de documento e 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 tiver determinado que uma regra CSS que envolve um recurso externo não se aplicar ao documento como ele está sendo criado, ele não o solicitará.

Esse comportamento especulativo pode ser usado para adiar o carregamento de imagens em CSS. Para isso, use JavaScript para determinar quando um elemento está na janela de visualização e, em seguida, aplique uma classe a esse elemento que aplique o estilo invocando 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 considerar um elemento que contém uma imagem de plano de fundo grande:

<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>

O elemento div.lazy-background normalmente 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 estiver 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 */
}

A partir daqui, 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. Isso vai carregar 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 Largest Contentful Paint (LCP)

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 são 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 decodificações de imagens.

No entanto, o carregamento lento é uma técnica que pode afetar a Maior LCP de pintura de conteúdo do seu site de maneira negativa, se você quiser muito usar essa técnica. 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 verificador 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 de uma imagem na janela de visualização pode não funcionar. Quando loading="lazy" é aplicado a uma imagem na janela de visualização, essa imagem é atrasada até que o navegador tenha certeza de que está nessa janela, o que pode afetar a LCP da página.

Nunca carregue lentamente imagens visíveis na janela de visualização durante a inicialização. Esse padrão afeta negativamente a LCP do site e, portanto, a experiência do usuário. Se você precisar de uma imagem na inicialização, carregue-a o mais rápido possível sem fazer o carregamento lento.

Bibliotecas de carregamento lento

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

  • Lazysizes é uma biblioteca de carregamento lento com todos os recursos que faz o carregamento lento de imagens e iframes. O padrão usado é muito parecido com os 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, cujo conteúdo é trocado em atributos src e/ou srcset, respectivamente. Ela usa o Intersection Observer, que pode ser polido, e pode ser estendido com vários plug-ins para fazer coisas como carregar vídeos lentamente. Saiba mais sobre o uso da Lazysizes (link em inglês).
  • vanilla-Lazyload é uma opção leve para carregamento lento de imagens, imagens de plano de fundo, vídeos, iframes e scripts. Ele aproveita o Intersection Observer, oferece suporte a imagens responsivas e permite o carregamento lento no nível do navegador.
  • lozad.js é uma outra opção leve que usa apenas Intersection Observer. Por isso, ele tem alto desempenho, mas precisa ser polyfill antes de ser usado em navegadores mais antigos.
  • Se você precisar de uma biblioteca de carregamento lento específica do React, considere usar o react-Slowload. Embora não use o Intersection Observer, ele fornece um método familiar de carregamento lento de imagens para quem está acostumado a desenvolver aplicativos com o React.