Infinite Scroll JavaScript: guia passo a passo para implementar
Implementar infinite scroll em JavaScript puro é mais simples do que parece. Neste guia, você vai construir um carregamento contínuo de conteúdo com poucas linhas de código, entendendo cada etapa e os erros que costumam aparecer no caminho.
Quando uma página carrega novos conteúdos conforme o usuário rola, ela usa o infinite scroll. O padrão é comum em feeds sociais e galerias, mas também aparece em listagens de produtos e resultados de busca. Em vez de paginar com botões, a experiência se torna contínua. Para implementar em JavaScript puro, sem depender de bibliotecas, o caminho mais limpo envolve a Intersection Observer API, que observa elementos na viewport sem travar a thread principal.
O resultado esperado: uma lista que cresce automaticamente até esgotar os dados, com feedback visual de carregamento e tratamento de erro. Pré-requisitos: conhecimento básico de JavaScript assíncrono (fetch, promises) e de manipulação do DOM. Nada além do navegador é necessário.
Passo 1: Estruturar o HTML com um sentinela
Crie um contêiner para os itens e um elemento vazio no final, que servirá como gatilho. Esse sentinela é o que o navegador vai observar.
<div id="lista"></div> <div id="sentinela"></div>
O sentinela não precisa ter conteúdo. Ele só existe para indicar o ponto onde novos itens devem aparecer. Erro comum: colocar o sentinela dentro do contêiner, o que pode confundir a lógica de inserção.
Passo 2: Configurar a Intersection Observer
No JavaScript, crie uma função que carrega mais itens e registre um observer no sentinela.
const sentinela = document.getElementById('sentinela'); let pagina = 1;
async function carregarMais() { const resposta = await fetch(/api/itens?pagina=${pagina}); const dados = await resposta.json(); dados.itens.forEach(item => { const div = document.createElement('div'); div.textContent = item.titulo; document.getElementById('lista').appendChild(div); }); pagina++; }
const observer = new IntersectionObserver((entradas) => { if (entradas[0].isIntersecting) { carregarMais(); } }, { rootMargin: '100px' });
observer.observe(sentinela);
A propriedade rootMargin adiciona uma margem de 100px antes do sentinela entrar na tela, permitindo que o carregamento comece antes do fim da página. Sem isso, o usuário pode ver um vazio incômodo durante o fetch.
Passo 3: Evitar múltiplas chamadas simultâneas
Se o observer disparar várias vezes antes da resposta chegar, você fará chamadas duplicadas. Use um flag simples para bloquear novas requisições enquanto uma está em andamento.
let carregando = false;
async function carregarMais() { if (carregando) return; carregando = true; try { // ... fetch e inserção ... } finally { carregando = false; } }
Um erro comum em implementações apressadas é ignorar esse controle. Em conexões lentas, o usuário pode acionar o scroll várias vezes e gerar dezenas de chamadas para a API. O flag resolve isso com uma linha.
Passo 4: Tratar o fim da lista e erros
Quando a API retornar uma lista vazia, pare o observer com observer.unobserve(sentinela). Caso contrário, o sentinela continuará na tela e o fetch nunca terminará.
if (dados.itens.length === 0) { observer.unobserve(sentinela); return; }
Para erros de rede, mostre uma mensagem discreta e permita que o usuário tente novamente. Um botão "Carregar mais" que reativa a função é uma saída simples. Nunca deixe o erro silencioso, pois o usuário pode pensar que a página travou.
Passo 5: Testar a experiência com dados reais
Use uma API fictícia, como a JSONPlaceholder, para simular paginação com _page e _limit. Por exemplo: https://jsonplaceholder.typicode.com/posts?_page=1&_limit=10. Isso permite testar o comportamento sem criar um backend próprio.
Um detalhe que passa despercebido: itens com alturas variáveis podem fazer o sentinela se mover de forma imprevisível. Teste com imagens de tamanhos diferentes e ajuste o rootMargin conforme necessário.
Checklist final
- O sentinela está fora do contêiner de itens.
- O observer usa
rootMarginpara carregar antes do fim. - Há um flag para evitar chamadas simultâneas.
- O observer é desativado quando a lista acaba.
- Erros de rede têm tratamento visível.
Com esses passos, o infinite scroll funciona em qualquer navegador moderno, sem bibliotecas extras. Para projetos maiores, avalie se a paginação tradicional não atende melhor a navegação, já que o scroll infinito dificulta o acesso ao rodapé e a indexação de conteúdo.
FAQ
O que é infinite scroll em JavaScript?
É uma técnica que carrega novos itens automaticamente quando o usuário rola até o fim da página. Em JavaScript puro, a Intersection Observer API é a forma mais eficiente de detectar esse momento, sem precisar de bibliotecas como jQuery.
Como detectar o fim da página em JavaScript?
Em vez de usar window.scroll e calcular alturas, observe um elemento sentinela com IntersectionObserver. Quando ele entra na viewport, você dispara a chamada para buscar mais dados.
Infinite scroll é melhor que paginação?
Depende do contexto. Em feeds sociais, o scroll contínuo melhora a imersão. Em lojas ou documentos longos, a paginação facilita a navegação e a indexação. Analise o comportamento do seu usuário antes de decidir.
Como evitar chamadas duplicadas no infinite scroll?
Use uma variável booleana que bloqueia novas requisições enquanto a anterior não termina. Isso previne que o scroll rápido dispare múltiplos fetches para a mesma página.
O que fazer quando a API retorna uma lista vazia?
Desative o observer com observer.unobserve(sentinela) e exiba uma mensagem de fim de conteúdo. Sem isso, o código continuará tentando buscar dados que não existem.
Posso usar infinite scroll sem Intersection Observer?
Sim, é possível com window.addEventListener('scroll'), mas o método exige cálculos manuais de posição e pode causar problemas de performance. O Intersection Observer é mais declarativo e eficiente.