Ahora se muestra IntersectionObserver

IntersectionObservers te avisa cuando un elemento observado entra en el viewport del navegador o sale de él.

Navegadores compatibles

  • 51
  • 15
  • 55
  • 12.1

Origen

Supongamos que deseas hacer un seguimiento cuando un elemento de tu DOM ingresa a la ventana de visualización visible. Es posible que desees hacerlo para poder cargar imágenes de forma diferida justo a tiempo o para saber si el usuario realmente está viendo un banner de anuncio determinado. Para ello, conecta el evento de desplazamiento o usa un temporizador periódico y llama a getBoundingClientRect() en ese elemento.

Sin embargo, este enfoque es muy lento, ya que cada llamada a getBoundingClientRect() obliga al navegador a cambiar el diseño de toda la página, lo que genera bloqueos considerables en tu sitio web. Los asuntos se acercan a imposibles cuando sabes que tu sitio se está cargando dentro de un iframe y deseas saber cuándo el usuario puede ver un elemento. El modelo de origen único y el navegador no te permitirán acceder a ningún dato de la página web que contiene el iframe. Este es un problema habitual en el caso de los anuncios, por ejemplo, que se cargan con frecuencia mediante iframes.

Para que esta prueba de visibilidad sea más eficiente, se diseñó IntersectionObserver, y llegó a todos los navegadores modernos. IntersectionObserver te permite saber cuándo un elemento observado entra en el viewport del navegador o sale de él.

Visibilidad de iframe

Cómo crear un IntersectionObserver

La API es bastante pequeña y se describe mejor a través de un ejemplo:

const io = new IntersectionObserver(entries => {
  console.log(entries);
}, {
  /* Using default options. Details below */
});

// Start observing an element
io.observe(element);

// Stop observing an element
// io.unobserve(element);

// Disable entire IntersectionObserver
// io.disconnect();

Con las opciones predeterminadas para IntersectionObserver, se llamará a tu devolución de llamada cuando el elemento se muestre parcialmente y cuando salga por completo del viewport.

Si necesitas observar varios elementos, es posible y se recomienda observar varios elementos usando la misma instancia de IntersectionObserver llamando a observe() varias veces.

Se pasa un parámetro entries a tu devolución de llamada, que es un array de objetos IntersectionObserverEntry. Cada objeto contiene datos de intersección actualizados para uno de los elementos observados.

🔽[IntersectionObserverEntry]
    time: 3893.92
    🔽rootBounds: ClientRect
        bottom: 920
        height: 1024
        left: 0
        right: 1024
        top: 0
        width: 920
    🔽boundingClientRect: ClientRect
    // ...
    🔽intersectionRect: ClientRect
    // ...
    intersectionRatio: 0.54
    🔽target: div#observee
    // ...

rootBounds es el resultado de llamar a getBoundingClientRect() en el elemento raíz, que es el viewport de forma predeterminada. boundingClientRect es el resultado de la llamada a getBoundingClientRect() en el elemento observado. intersectionRect es la intersección de estos dos rectángulos y te indica de manera efectiva qué parte del elemento observado es visible. intersectionRatio está estrechamente relacionado y te indica qué cantidad del elemento es visible. Con esta información a tu disposición, ahora puedes implementar funciones como la carga justo a tiempo de elementos antes de que se muestren en la pantalla. de manera eficiente.

Proporción de intersección.

Los elementos IntersectionObserver entregan sus datos de forma asíncrona, y tu código de devolución de llamada se ejecutará en el subproceso principal. Además, la especificación indica que las implementaciones de IntersectionObserver deben usar requestIdleCallback(). Esto significa que la llamada a la devolución de llamada proporcionada tiene una prioridad baja y la realizará el navegador durante el tiempo de inactividad. Esta es una decisión de diseño consciente.

Elementos div de desplazamiento

No me gusta mucho desplazar dentro de un elemento, pero no estoy aquí para juzgar, y tampoco lo es IntersectionObserver. El objeto options toma una opción root que te permite definir una alternativa al viewport como raíz. Es importante tener en cuenta que root debe ser un elemento principal de todos los elementos observados.

¡Intersectar todos los elementos!

¡No! Mal desarrollador Eso no tiene en cuenta el uso de los ciclos de CPU del usuario. Pensemos en un desplazamiento infinito como ejemplo: en ese caso, es definitivamente recomendable agregar centinelas al DOM y observarlos (y reciclarlos). Deberías agregar un centinela cerca del último elemento de la barra de desplazamiento infinito. Cuando aparezca ese centinela, puedes usar la devolución de llamada para cargar los datos, crear los siguientes elementos, adjuntarlos al DOM y cambiar la posición del centinela según corresponda. Si reciclas correctamente el centinela, no se necesita ninguna llamada adicional a observe(). El IntersectionObserver sigue funcionando.

Desplazamiento infinito

Quiero recibir más actualizaciones

Como se mencionó antes, la devolución de llamada se activará una sola vez cuando el elemento observado se muestre parcialmente y otra cuando haya salido del viewport. De esta manera, IntersectionObserver te da una respuesta a la pregunta “¿El elemento X está a la vista?”. Sin embargo, en algunos casos de uso, eso podría no ser suficiente.

Ahí es donde entra en juego la opción threshold. Te permite definir un array de umbrales de intersectionRatio. Se llamará a tu devolución de llamada cada vez que intersectionRatio cruce uno de estos valores. El valor predeterminado de threshold es [0], lo que explica el comportamiento predeterminado. Si cambiamos threshold a [0, 0.25, 0.5, 0.75, 1], recibiremos una notificación cada vez que se muestre un cuarto más del elemento:

Animación de umbral.

¿Tienes alguna otra opción?

Por el momento, solo hay una opción adicional para las anteriores. rootMargin te permite especificar los márgenes de la raíz, lo que te permite aumentar o reducir el área que se usa para las intersecciones. Estos márgenes se especifican con una cadena de estilo CSS, a la "10px 20px 30px 40px", con la especificación de los márgenes superior, derecho, inferior e izquierdo, respectivamente. En resumen, la estructura de opciones IntersectionObserver ofrece las siguientes opciones:

new IntersectionObserver(entries => {/* … */}, {
  // The root to use for intersection.
  // If not provided, use the top-level document's viewport.
  root: null,
  // Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
  // If an explicit root element is specified, components may be percentages of the
  // root element size.  If no explicit root element is specified, using a
  // percentage is an error.
  rootMargin: "0px",
  // Threshold(s) at which to trigger callback, specified as a ratio, or list of
  // ratios, of (visible area / total area) of the observed element (hence all
  // entries must be in the range [0, 1]).  Callback will be invoked when the
  // visible ratio of the observed element crosses a threshold in the list.
  threshold: [0],
});

Comando mágico de <iframe>

Las IntersectionObserver se diseñaron específicamente teniendo en cuenta los servicios de anuncios y los widgets de redes sociales, que con frecuencia usan elementos <iframe> y podrían beneficiarse de saber si están a la vista. Si una <iframe> observa uno de sus elementos, desplazarse por <iframe> y por la ventana que contiene el <iframe> activará la devolución de llamada en los momentos adecuados. Sin embargo, para el último caso, rootBounds se establecerá como null para evitar que se filtren datos entre los orígenes.

¿De qué se trata IntersectionObserver no?

Ten en cuenta que IntersectionObserver no es intencionalmente ni perfecto de píxeles ni latencia baja. Si las usas para implementar iniciativas, como las animaciones que dependen de los desplazamientos, seguramente fallarán, ya que los datos estarán desactualizados, en sentido estricto, para el momento en que los uses. La explicación incluye más detalles sobre los casos de uso originales de IntersectionObserver.

¿Cuánto trabajo puedo hacer en la devolución de llamada?

Breve y genial: Si dedicas demasiado tiempo a la devolución de llamada, se retrasará la app, y se aplicarán todas las prácticas habituales.

Adelántate y cruza los elementos

La compatibilidad de los navegadores con IntersectionObserver es buena, ya que está disponible en todos los navegadores modernos. Si es necesario, se puede usar un polyfill en navegadores más antiguos y está disponible en el repositorio de WICG. Desde luego, no obtendrás los beneficios de rendimiento que obtendrías si usas ese polyfill que le daría una implementación nativa.

Ya puedes comenzar a usar IntersectionObserver. Cuéntanos lo que se te ocurrió.