Descobrir posição do scroll de um elemento com JS

Neste artigo você vai aprender a como descobrir posição do scroll de um elemento, utilizando JavaScript e de modo simples!

Descobrir posição do scroll de um elemento

Conteúdo disponível em vídeo:

Fala programador(a), beleza? Bora aprender mais sobre DOM e posição dos elementos na tela!

Para saber a posição do elemento, primeiramente você vai precisar selecioná-lo com algum método de document

Alguns disponíveis:

  • getElementsByName;
  • getElementById;
  • getElementsByClassName;
  • querySelector;
  • querySelectorAll;

Vamos então criar uma situação hipotética e utilizar algum deles para selecionar o elemento, veja o HTML:

<p class="normal">Olá Mundo</p>
<p class="normal">Olá Mundo 2</p>
<p class="normal">Olá Mundo 3</p>
<p id="posicao">Posição deste elemento</p>

Neste HTML vamos buscar a posição do elemento com id posicao, você deve adaptar para o elemento do seu site

Então vamos selecionar ele com JavaScript:

var p = document.querySelector('#posicao');

posicoes = p.getBoundingClientRect();

console.log(posicoes);

Na primeira linha o elemento foi selecionado, depois utilizamos o método getBoundingClientRect para resgatar todos os dados de posição de um elemneto

Agora na variável posicoes, conforme console.log, diversas informações sobre o mesmo são exibidas em forma de objeto, veja:

[object DOMRect] {
  bottom: 136,
  height: 18,
  left: 8,
  right: 622,
  toJSON: function toJSON() { [native code] },
  top: 118,
  width: 614,
  x: 8,
  y: 118
}

E agora podemos saber a posição do elemento, veja a propriedade top, isso quer dizer que este elemento está a 118px do topo da página

Temos também as suas dimensões, coordenadas e muito mais

Agora você consegue obter a posição de qualquer elemento na tela! 😀

Conclusão

Neste artigo você aprendeu a como descobrir posição do scroll de um elemento

Utilizamos um método de DOM chamado getBoundingClientRect, este método cria um objeto a partir de um elemento

Este objeto contém informações de posição e também tamanho do elemento na tela

Onde você pode resgatar qual a posição exata o mesmo está

Confira também nosso catálogo de cursos gratuitos, com aulas semanais no YouTube

Por que esse valor muda quando você rola a página:

Se liga nisso, porque é aqui que a maioria se perde

O getBoundingClientRect devolve a posição do elemento em relação à área visível da janela, e não em relação ao topo do documento

Ou seja: role a página, chame o método de novo e o top vem diferente

É por isso que ele serve tão bem pra saber a posição do scroll: o número te diz o quanto falta pro elemento chegar no topo da tela

E se você quer a posição fixa, contando desde o começo do documento? Aí soma o quanto a página já rolou:

const p = document.querySelector('#posicao')

const posicaoAbsoluta = p.getBoundingClientRect().top + window.scrollY

console.log(posicaoAbsoluta)

Esse valor não muda enquanto tu rola, ele só muda se o layout mudar

Guarda essa diferença: relativo à tela (getBoundingClientRect) e relativo ao documento (soma com o scroll) 😀

E o scroll DENTRO de um elemento?

Tem dois cenários bem diferentes e o pessoal mistura os dois

Um é a página inteira rolando, outro é uma div com barra de rolagem própria (aquela com overflow)

Pra saber quanto essa div já rolou por dentro, o caminho é outro:

const caixa = document.querySelector('#caixa')

console.log(caixa.scrollTop) // quanto já rolou por dentro
console.log(caixa.scrollHeight) // altura total do conteúdo
console.log(caixa.clientHeight) // altura visível da caixa

Com esses três tu descobre até quando o usuário chegou no fim:

caixa.addEventListener('scroll', () => {
const chegouNoFim = caixa.scrollTop + caixa.clientHeight >= caixa.scrollHeight

if (chegouNoFim) {
console.log('acabou o conteúdo')
}
})

Massa pra carregar mais itens, liberar um botão de aceite, essas coisas

O jeito atual de saber quando o elemento aparece na tela:

Aqui vai a parte que envelheceu desde que escrevi este post

Na época, o padrão era ficar calculando a posição a cada evento de scroll, o que dispara MUITO e pesa na página

Hoje, quando tua intenção é só saber se o elemento entrou ou saiu da tela, dá pra deixar o navegador avisar você:

const alvo = document.querySelector('#posicao')

const observador = new IntersectionObserver((entradas) => {
entradas.forEach((entrada) => {
if (entrada.isIntersecting) {
console.log('o elemento apareceu na tela')
}
})
})

observador.observe(alvo)

A analogia é simples: em vez de você perguntar mil vezes ‘já chegou?’, o navegador te dá um toque quando chega

Use getBoundingClientRect quando quer o NÚMERO da posição, e o observador quando quer só o gatilho de apareceu ou sumiu

Bora ver na prática? Cola o código aí e rola a página =)

Erros comuns na hora de pegar a posição:

Tome cuidado com estes três, já me ferrei com todos eles

O primeiro: rodar o código antes do elemento existir no HTML

Se o querySelector devolve null, o script foi executado antes da página montar aquele trecho, coloca ele no final do body ou dentro do evento de carregamento

O segundo: elemento escondido com display none devolve tudo zerado

Não é bug, é que sem ocupar espaço na tela ele não tem posição nenhuma pra reportar

O terceiro: os valores podem vir quebrados, tipo 118.5, por causa de zoom, borda ou fonte

Se você precisa comparar com um número redondo, arredonda antes com Math.round e evita dor de cabeça

E se eu quiser ROLAR até o elemento?

É o outro lado da mesma moeda, e quem busca posição do scroll normalmente quer isso em seguida

O caminho curto é pedir pro próprio elemento se apresentar:

const p = document.querySelector('#posicao')

p.scrollIntoView({ behavior: 'smooth', block: 'start' })

E se você quer controlar a parada, tipo deixar um respiro por causa de um menu fixo no topo, aí usa a posição que a gente calculou lá em cima:

const topo = p.getBoundingClientRect().top + window.scrollY

window.scrollTo({ top: topo - 80, behavior: 'smooth' })

O 80 aí é só o espaço que tu quer sobrando, ajusta pro tamanho do teu menu

Um detalhe de sintaxe, já que o post tem uns anos de estrada: hoje o comum é declarar com const em vez de var, e declarar a variável posicoes também, pra ela não virar global sem querer

Fica assim:

const p = document.querySelector('#posicao')

const posicoes = p.getBoundingClientRect()

console.log(posicoes)

O resultado é o mesmo, muda só o cuidado com o escopo

Leia também

Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 30min

Blog | Mais populares