Existem mais de 30 respostas para essa pergunta e nenhuma delas usa a solução JS pura e incrivelmente simples que eu tenho usado. Não é necessário carregar o jQuery apenas para resolver isso, pois muitos outros estão pressionando.
Para saber se o elemento está dentro da viewport, devemos primeiro determinar a posição dos elementos no corpo. Não precisamos fazer isso recursivamente, como eu pensava. Em vez disso, podemos usar element.getBoundingClientRect()
.
pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;
Este valor é a diferença Y entre a parte superior do objeto e a parte superior do corpo.
Devemos então dizer se o elemento está à vista. A maioria das implementações pergunta se o elemento completo está dentro da janela de exibição, então é isso que abordaremos.
Primeiro de tudo, a posição superior da janela é: window.scrollY
.
Podemos obter a posição inferior da janela adicionando a altura da janela à sua posição superior:
var window_bottom_position = window.scrollY + window.innerHeight;
Vamos criar uma função simples para obter a posição superior do elemento:
function getElementWindowTop(elem){
return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0;
}
Esta função retornará a posição superior do elemento dentro da janela ou retornará 0
se você passar algo diferente de um elemento com o .getBoundingClientRect()
método Esse método existe há muito tempo, portanto você não precisa se preocupar com o fato de seu navegador não o suportar.
Agora, a posição superior do nosso elemento é:
var element_top_position = getElementWindowTop(element);
E ou a posição inferior do elemento é:
var element_bottom_position = element_top_position + element.clientHeight;
Agora, podemos determinar se o elemento está dentro da viewport, verificando se a posição inferior do elemento é menor que a posição superior da viewport e verificando se a posição superior do elemento é maior que a posição inferior da viewport:
if(element_bottom_position >= window.scrollY
&& element_top_position <= window_bottom_position){
//element is in view
else
//element is not in view
A partir daí, você pode executar a lógica para adicionar ou remover uma in-view
classe em seu elemento, com a qual poderá lidar posteriormente com efeitos de transição em seu CSS.
Estou absolutamente surpreso por não encontrar essa solução em nenhum outro lugar, mas acredito que essa é a solução mais limpa e eficaz e não exige que você carregue o jQuery!