Como saber si un elemento HTML se ve en pantalla en una web con scroll. IntersectionObserver

Todos los que llevamos un tiempo programando webs nos hemos tenido que enfrentar al scroll. ¿Qué vel el usuario en su pantalla? ¿Por que punto del div (párrafo, imagen,…) está?. Muchas veces la solución es un enrevesado conjunto de cálculos. Por suerte los navegadores han implementado un solución en el javascripr que permite hacerlo fácilmente: IntersectionObserver

Explicado de forma muy resumida, IntersectionObserver invoca a una función cuando el elemento html que le indiquemos se muestre en la pantalla en distintos porcentajes.

Primero veamos como se crea un IntersectionObserver:

let observer = new IntersectionObserver(handleIntersect, options);
observer.observe(element);

handleIntersect es la función a la que llamara el observer. Se le pasa un objeto entries que es un array de objetos entry correspondiente a vrios eventos de intersección asociados (por lo general es solo uno). Cada uno de los objetos entry tiene las siguientes propiedades:

entry.boundingClientRect
entry.intersectionRatio
entry.intersectionRect
entry.isIntersecting
entry.rootBounds
entry.target
entry.time

option es un objeto con tres posibles campos:

  • root: Indica que elemento que es usado como viewport para comprobar la visibilidad de nuestro elemento. Debe ser ancestro del nuestro. Por defecto es el viewport del navegador.
  • rootMargin: Delimita los margenes del elemento root que se ha de tener en cuanta al calcular la intersecciones. Por defecto son cero.
  • threshold: Es un número o un array que indican a que porcentaje de visibilidad se llama a la función asociada al observer. Su valor debe estar definido entre 0 (0%) y 1 (100%)

element es el elemento que el observer “estará vigilando”

Veamos un ejemplo completo:

<html>
<style>
    p {
        font-size: 120px;
        border: 2px solid black;    
    }
</style>

<body>
    <p id="p0">0</p>
    <p id="p1">1</p>
    <p id="p2">2</p>
    <p id="p3">3</p>
    <p id="p4">4</p>
    <p id="p5">5</p>
    <p id="p6">6</p>
    <p id="p7">7</p>
    <p id="p8">8</p>
    <p id="p9">9</p>    
</body>

<script>
    let element = document.getElementById("p5");

    let options = {
        root: null, //document.getElementById()
        rootMargin: '0px',
        threshold: [0, 0.5, 1.0]
    }

    let observer = new IntersectionObserver(handleIntersect, options);
    observer.observe(element);

    function handleIntersect(entries){
        entries.forEach(entry => {
            console.log("Elemento con id "+entry.target.id+"se muestra en pantalla en un porcentaje de: "+(entry.intersectionRatio*100));
        });
    }
</script>
</html>