A mesma filosofia de melhorar a experiência do usuário também se aplica ao carregamento lento de imagens. As imagens são um dos maiores contribuintes para o peso da página quando estamos navegando em sites. Carregá-los de maneira ideal pode melhorar o desempenho e economizar largura de banda.
Neste tutorial, aprenderemos sobre diferentes métodos de carregamento lento de imagens.
A necessidade de carregamento lento de imagens
Começaremos o tutorial aprendendo primeiro por que você deve se preocupar com o carregamento lento de imagens. Digamos que você esteja criando um site de portfólio para um fotógrafo e ele exiba todas as suas melhores imagens em uma única página.
Nem todo mundo vai rolar até o final da página para ver todas as imagens. No entanto, as imagens ainda seriam baixadas pelo navegador do usuário. Isso fica evidente na demonstração do CodePen abaixo:
Mesmo que você não passe da primeira imagem na demonstração acima, verá que o navegador carregou todas as imagens. A captura de tela a seguir do Rede guia das ferramentas de desenvolvedor do meu navegador mostra que 38 solicitações foram feitas com cerca de 2,5 MB de dados transferidos. O navegador baixou um total de 19 imagens com redirecionamentos dobrando o número de solicitações.
Vamos agora tentar melhorar ou otimizar o carregamento da imagem para economizar recursos.
Carregamento lento de imagens usando HTML
A maneira mais fácil de carregar imagens preguiçosamente envolve o uso de loading
atributo. Todos os navegadores modernos suportam o loading
atributo em imagens que pode ser usado para instruir o navegador a impedir o carregamento de uma imagem se ela estiver fora da tela e apenas começar a carregá-la quando o usuário rolar a tela o suficiente para que ela fique visível.
O loading
atributo pode aceitar dois valores possíveis:
O primeiro valor é eager
que informa ao navegador para carregar a imagem imediatamente, mesmo que ela não esteja atualmente na janela de visualização. Este é o comportamento padrão dos navegadores.
O segundo valor é lazy
que informa aos navegadores para adiar o carregamento de uma imagem até que ela atinja uma distância específica da janela de visualização. Esta distância é definida pelo navegador. Configurando o valor do atributo loading para lazy
pode potencialmente economizar largura de banda para os clientes.
É importante lembrar que os navegadores carregam apenas imagens preguiçosas que não estão visíveis na janela de visualização. Normalmente, as imagens em uma página da Web são colocadas junto com outro texto que as empurra para fora da janela de visualização. Você não precisa fazer nada de especial para garantir que as imagens carreguem lentamente neste caso.
No entanto, considere nosso exemplo neste tutorial em que a página da Web contém apenas imagens. Nesse cenário, torna-se importante que você mencione o tamanho das imagens se quiser que elas carreguem lentamente. Caso contrário, todas as imagens terão largura e altura zero inicialmente. Isso fará com que o navegador pense que todas as imagens estão realmente visíveis na janela de visualização e carregará todas de uma vez.
Especificar explicitamente a largura e a altura da imagem neste caso empurraria algumas imagens para fora da janela de visualização. Você é livre para especificar as dimensões da imagem usando o width
e height
Atributos HTML ou em CSS.
Aqui está a marcação que carregará as imagens preguiçosamente:
1 |
loading="lazy" src="https://picsum.photos/id/628/1080/1080" width="600" height="600">
|
Como eu disse anteriormente, você também pode especificar as dimensões da imagem em CSS e remover o width
e height
atributos da marcação:
1 |
loading="lazy" src="https://picsum.photos/id/628/1080/1080">
|
O CSS correspondente seria:
1 |
img { |
2 |
width: 600px; |
3 |
height: 600px; |
4 |
}
|
A seguinte demonstração do CodePen mostra o carregamento lento em ação:
O Rede guia nas ferramentas de desenvolvedor do meu navegador mostra que apenas quatro imagens foram baixadas desta vez com cerca de 450kb de transferência de dados. Há um total de 19 imagens na página, o que significa que outras quinze serão baixadas lentamente. Em termos de largura de banda, isso se traduz em uma economia de cerca de 80%.
Uma coisa importante a ter em mente aqui é que, embora não haja nenhum script envolvido, o carregamento lento de imagens só funciona quando o JavaScript está ativado. Isso é feito para evitar o rastreamento da posição de rolagem de um usuário por imagens estrategicamente posicionadas.
Como o navegador determina quando deve baixar as imagens que devem ser carregadas lentamente? As condições exatas que acionam o download de imagens com carregamento lento variam entre os navegadores. No entanto, dois fatores principais parecem ser a distância da janela de visualização e a velocidade da rede.
Se você deseja controlar exatamente quando as imagens de carregamento lento são baixadas, você terá que usar JavaScript.
Carregamento lento de imagens usando JavaScript
Agora vamos aprender como usar JavaScript para carregar imagens preguiçosamente. Isso nos dará mais controle sobre todo o processo. Se você acha que o carregamento lento padrão não é agressivo o suficiente, você pode criar seu próprio script de carregamento lento usando a API Intersection Observer.
Antes de escrever qualquer JavaScript, precisamos fazer algumas alterações em nossa marcação:
1 |
class="lazy-load" data-src="https://picsum.photos/id/628/1080/1080">
|
Nosso img
tags agora conterão uma classe chamada lazy-load
para nos ajudar a identificar quais imagens precisam ser carregadas lentamente. Em vez de um src
atributo, o img
tags usarão o data-src
atributo para acompanhar o caminho da imagem. Isso evita que a imagem inicie o download imediatamente.
A API Intersection Observer nos permite detectar se nosso elemento de destino está em interseção com algum de seus elementos ancestrais ou com a janela de visualização do documento. Nós usaremos o IntersectionObserver()
construtor para criar nosso IntersectionObserver
objeto. O construtor aceita uma função de retorno de chamada como seu primeiro parâmetro e um objeto opcional para personalizar o comportamento do observador como segundo parâmetro.
A função callback que passamos para o construtor recebe dois parâmetros. O primeiro é uma matriz de elementos de interseção e o segundo é o próprio observador. As opções de personalização permitem que você especifique o elemento raiz com o qual deseja verificar a interseção, a margem raiz que adiciona um valor extra de deslocamento ao elemento raiz e um limite para determinar quando o navegador deve começar a relatar a interseção.
Aqui está o código para nosso objeto observador de interseção:
1 |
function preload_image(img) { |
2 |
img.src = img.dataset.src; |
3 |
console.log(`Loading ${img.src}`); |
4 |
}
|
5 |
|
6 |
const config_opts = { |
7 |
rootMargin: '200px 200px 200px 200px' |
8 |
};
|
9 |
|
10 |
let observer = new IntersectionObserver(function(entries, self) { |
11 |
for(entry of entries) { |
12 |
if(entry.isIntersecting) { |
13 |
let elem = entry.target; |
14 |
preload_image(elem); |
15 |
self.unobserve(elem); |
16 |
}
|
17 |
}
|
18 |
}, config_opts); |
Forneci uma margem de 200px em todos os lados de nosso elemento raiz ou viewport neste caso. Nosso observador de interseção se tornará ativo sempre que qualquer imagem estiver dentro de 200px da viewport. O valor limite é definido como 0 por padrão. Um valor de zero significa que o retorno de chamada do preload_image()
A função será chamada assim que um pequeno pedaço da imagem estiver dentro dos limites especificados. O unobserve()
O método informa ao navegador para parar de observar essa imagem específica para outras interseções.
O preload_image()
função recebe o valor do data-src
atributo para a nossa imagem e aplica-o ao src
atributo. Isso aciona um download da nossa imagem.
Tudo o que precisamos fazer agora é consultar todas as imagens em nosso documento e, em seguida, dizer ao observador para observá-las todas em busca de interseção. Aqui está o código que consegue isso para nós.
1 |
let images = document.querySelectorAll('img.lazy-load'); |
2 |
|
3 |
for(image of images) { |
4 |
observer.observe(image); |
5 |
}
|
Você notou que estamos usando o img.lazy-load
seletor para consultar nossas imagens? Esta classe nos ajuda a identificar facilmente todas as imagens que queremos carregar lentamente. As imagens sem esta classe serão carregadas normalmente.
Aqui está uma demonstração do CodePen para ver se nossas imagens estão realmente carregando lentamente ou não.
Desta vez o Rede guia nas ferramentas de desenvolvedor do meu navegador mostra que apenas duas imagens foram baixadas anteriormente com uma transferência total de dados de cerca de 192kb. Nossa economia de largura de banda agora subiu para 92% em comparação com nossa demonstração original.
Admito que tornei o observador de interseção muito agressivo para carregar apenas imagens muito próximas da janela de visualização. No entanto, essa é a beleza de implementar a funcionalidade por conta própria.
Pensamentos finais
Carregar imagens preguiçosamente é vantajoso para todos. Isso reduzirá a carga em seu servidor enquanto economiza largura de banda dos usuários. Lembre-se de que os dados, especialmente dados móveis, são bastante caros em alguns lugares do mundo.
Agora que os navegadores vêm com suporte nativo para carregar imagens lentamente, é apenas uma questão de fazer pequenas alterações em sua marcação para aproveitar ao máximo o recurso. Os navegadores também são inteligentes o suficiente para determinar o momento ideal em que devem carregar lentamente uma imagem com base na velocidade da rede e no local da imagem. Você também pode implementar a funcionalidade de forma relativamente fácil com o uso da API Intersection Observer.
Uma coisa importante a ter em mente aqui é que nenhuma dessas técnicas funcionará se o JavaScript estiver desabilitado no lado do usuário.