Adiar imagens fora da tela em dispositivos móveis
Adiar imagens fora da tela em dispositivos móveis

Adiamento de Imagens em Dispositivos Móveis: o padrão
O desempenho móvel é frequentemente limitado pela latência de rede (RTT) e pela disponibilidade de CPU da thread principal. Adiar imagens fora da tela em dispositivos móveis resolve ambos os problemas, prevenindo a contenção de largura de banda no caminho crítico de renderização e distribuindo os custos de decodificação de imagens ao longo da duração da sessão.
Este documento explica como adiar imagens de forma eficaz em dispositivos móveis, quando utilizá-lo e aborda as restrições mecânicas específicas dos viewports móveis.

Table of Contents!
1. Adiar imagens fora da tela em dispositivos móveis: lazy loading nativo
Quando um navegador carrega uma página, ele abre um número limitado de conexões paralelas (dependendo de muitos fatores, mas 6 por domínio é uma média comum). Se essas conexões forem usadas para baixar imagens fora da tela (por exemplo, um logotipo no rodapé ou slide de carrossel), o download de recursos críticos (tipicamente a imagem LCP, scripts importantes e fontes competirão por slots e largura de banda). Este fenómeno, conhecido como Contenção de Rede, degrada diretamente os Core Web Vitals.
Ao adiar imagens fora da tela usando o atributo nativo loading, podemos priorizar recursos importantes e otimizar o Caminho Crítico de Renderização. O navegador busca apenas o que é imediatamente visível, reservando largura de banda para os recursos que impactam estritamente o First Contentful Paint (FCP) e o Largest Contentful Paint (LCP). O método de lazy loading nativo transfere essa lógica de priorização para o mecanismo interno muito mais rápido do navegador, eliminando a necessidade de bibliotecas JavaScript antigas e lentas.
Implementação
Para todas as imagens abaixo do viewport inicial ("the fold"), adicione o atributo loading="lazy".
<!-- Standard Deferred Image -->
<img src="product-detail.jpg"
loading="lazy"
alt="Side view of the chassis"
width="800"
height="600"
decoding="async">
Como o lazy loading funciona em dispositivos móveis: A Heurística do Navegador
O lazy loading nativo é superior às soluções JavaScript porque o navegador ajusta o limiar de carregamento (quando uma imagem é acionada para download) com base no Tipo de Conexão Efetiva (ECT).
- Em 4G/WiFi: O motor Blink (Chrome/Edge) emprega um limiar conservador (por exemplo, 1250px). Ele assume baixa latência e busca a imagem apenas quando o utilizador está relativamente próximo do viewport.
- Em 3G/Slow-2G: O limiar expande (por exemplo, 2500px). O navegador inicia o pedido muito mais cedo em relação à posição de scroll para compensar os altos tempos de ida e volta, garantindo que a imagem esteja pronta antes do utilizador a rolar para a área visível.
Exceção Crítica: O Candidato a LCP
Uma regressão de desempenho comum ocorre quando os programadores aplicam loading="lazy" ao elemento Largest Contentful Paint (LCP) (tipicamente a imagem hero). Isto atrasa a busca até que o layout esteja completo.
Estratégia Correta para o LCP: A imagem LCP deve ser carregada de forma eager e priorizada.
<!-- Hero Image: Eager and Prioritized -->
<img src="hero.jpg"
alt="Summer Collection"
width="1200"
height="800"
loading="eager"
fetchpriority="high"> 2. Complexidades móveis: Viewport e Toque
Os viewports móveis introduzem desafios de renderização específicos que a implementação nativa lida de forma mais robusta do que soluções baseadas em scripts.
- O Viewport: A área retangular visível da janela do navegador. Em dispositivos móveis, esta é dinâmica; muda de dimensões com base na orientação do dispositivo (retrato vs. paisagem) e no estado do chrome do navegador (barras de URL retraídas).
- The Fold: A borda inferior exata do viewport. É o limiar que separa o conteúdo visível do conteúdo fora da tela.
- Above the Fold: Qualquer conteúdo visível imediatamente ao carregar a página sem necessidade de scroll. As imagens aqui são frequentemente críticas e quase nunca devem ter lazy loading.
- Below the Fold: Qualquer conteúdo localizado verticalmente abaixo do fold. Este conteúdo é Não Crítico e deve ser adiado até que o utilizador role para perto dele.

O Viewport Dinâmico
Nos navegadores móveis, a altura do viewport (vh) é fluida. Quando o utilizador inicia um scroll por toque, a barra de URL e os controlos de navegação frequentemente retraem, alterando o tamanho da área visível.
As bibliotecas JavaScript de adiamento de imagens geralmente calculam a altura do viewport (window.innerHeight) apenas uma vez no início do carregamento da página. Quando os navegadores móveis redimensionam dinamicamente a área visível ao ocultar a barra de URL durante o scroll, os métodos JavaScript continuam a usar o valor de altura antigo e menor. Isto fazia com que as imagens permanecessem descarregadas mesmo quando entravam fisicamente na área expandida do viewport, causando uma má UX para os visitantes.
O Tratamento Nativo resolve este problema uma vez que o motor de layout interno do navegador rastreia o viewport visual automaticamente, garantindo que os acionadores disparam independentemente de quaisquer alterações no tamanho do viewport.
3. Decodificação de Imagens em Dispositivos Móveis e Limitação de CPU
Os dispositivos móveis têm CPU limitada e a decodificação de imagens em dispositivos móveis pode ser relativamente lenta e cara. Converter um JPEG num bitmap requer muitos ciclos de CPU. Num processador móvel, decodificar uma sequência de imagens maiores pode bloquear a thread principal por 50ms–100ms cada, causando latência de entrada.
A Solução: content-visibility
Para resolver isto, podemos usar a propriedade e valor CSS content-visibility: auto. Esta propriedade atua como um padrão para "Renderização Lazy." Ela instrui o navegador a ignorar as fases de layout e pintura para elementos fora da tela por completo. O elemento existe no DOM, mas não existe na Render Tree até se aproximar do viewport.
Como esta otimização funciona ao ignorar a renderização da subárvore de um elemento, não é possível aplicá-la diretamente a uma tag <img> (que não possui subárvore). Deve-se aplicar content-visibility ao contentor do produto ou cartão de imagem que hospeda essas imagens e o seu conteúdo
@media (max-width: 768px) {
.image-card, .product-card {
/* Skip rendering of the container and its children */
content-visibility: auto;
/* Essential: Prevents container from collapsing to 0px height */
contain-intrinsic-size: auto 300px;
}
}
Isto garante que, mesmo que uma imagem seja descarregada, o navegador não paga o custo de layout/pintura até que o utilizador realmente role até ela.
4. Metodologias Legacy: Por que evitá-las
Antes do suporte nativo, os programadores dependiam de JavaScript para o adiamento de imagens em dispositivos móveis. Estes métodos ainda são amplamente utilizados, mas devem ser considerados como dívida técnica!
A Era do "Scroll Handler" (2010–2016)
As primeiras implementações anexavam event listeners ao evento scroll.
// OBSOLETE: Do not use
window.addEventListener('scroll', () => {
images.forEach(img => {
if (img.getBoundingClientRect().top < window.innerHeight) {
img.src = img.dataset.src;
}
});
});
Bloqueio da Thread Principal: O evento scroll dispara dezenas de vezes por segundo. Executar lógica e calcular layout (getBoundingClientRect) durante o scroll ativo causava quedas de frames (jank).
Layout Thrashing: Consultar propriedades geométricas força o navegador a recalcular sincronamente o estilo de layout, uma operação computacionalmente cara em CPUs móveis.
A Era do IntersectionObserver (2016–2019)
A API IntersectionObserver melhorou o desempenho ao observar assincronamente as alterações na visibilidade dos elementos.
// DEPRECATED: Use native loading where possible
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
Dependência de Script: Requer execução de JavaScript. Se a thread principal estiver ocupada a hidratar um framework (React/Vue), as imagens permanecem descarregadas mesmo que estejam no viewport.
Falta de Consciência de Rede: Ao contrário do loading nativo, o IntersectionObserver utiliza margens fixas (por exemplo, rootMargin: '200px'). Não expande automaticamente o seu buffer em redes lentas, levando a "flashes brancos" para utilizadores com conexões fracas.
Ask AI why your INP spiked.
CoreDash is the only RUM tool with MCP support. Connect it to your AI agent and query your Core Web Vitals data in natural language. No more clicking through dashboards.
See How It Works
