24 de octubre de 2022

Desplazamiento

El evento scroll permite reaccionar al desplazamiento de una página o elemento. Hay bastantes cosas buenas que podemos hacer aquí.

Por ejemplo:

  • Mostrar/ocultar controles o información adicional según el lugar del documento en el que se encuentre el/la usuario/a.
  • Cargar más datos cuando el/la usuario/a se desplaza hacia abajo hasta el final del documento.

Aquí hay una pequeña función para mostrar el desplazamiento actual:

window.addEventListener('scroll', function() {
  document.getElementById('showScroll').innerHTML = window.pageYOffset + 'px';
});

In action:

Desplazamiento actual = Desplazamiento de la ventana

El evento scroll funciona tanto en window como en los elementos desplazables.

Evitar el desplazamiento

¿Qué hacemos para que algo no se pueda desplazar?

No podemos evitar el desplazamiento utilizando event.preventDefault() oyendo al evento onscroll, porque este se activa después de que el desplazamiento haya ocurrido.

Pero podemos prevenir el desplazamiento con event.preventDefault() en un evento que cause el desplazamiento, por ejemplo en el evento keydown para pageUp y pageDown.

Si añadimos un manejador de eventos a estos eventos y un event.preventDefault() en el manejador, entonces el desplazamiento no se iniciará.

Hay muchas maneras de iniciar un desplazamiento, la más fiable es usar CSS, la propiedad overflow.

Aquí hay algunas tareas que puede resolver o revisar para ver aplicaciones de onscroll.

Tareas

importancia: 5

Crear una página interminable. Cuando un visitante la desplace hasta el final, se auto-añadirá la fecha y hora actual al texto (así el visitante podrá seguir desplazándose)

Así:

Por favor tenga en cuenta dos características importantes del desplazamiento:

  1. El scroll es “elástico”. En algunos navegadores/dispositivos podemos desplazarnos un poco más allá del inicio o final del documento (se muestra un espacio vacío abajo, y luego el documento “rebota” automáticamente a la normalidad).
  2. El scroll es impreciso. Cuando nos desplazamos hasta el final de la página, podemos estar de hecho como a 0-50px del fondo del documento real.

Así que, “desplazarse hasta el final” debería significar que el visitante no está a más de 100px del final del documento.

P.D. En la vida real podemos querer mostrar “más mensajes” o “más bienes”.

Abrir un entorno controlado para la tarea.

El núcleo de la solución es una función que añade más fechas a la página (o carga más cosas en la vida real) mientras estamos en el final de la página.

Podemos llamarlo inmediatamente o agregarlo como un manejador de window.onscroll.

La pregunta más importante es: “¿Cómo detectamos que la página se desplaza hasta el fondo?”

Usaremos las coordenadas de la ventana.

El documento está representado (y contenido) dentro de la etiqueta <html>, que es document.documentElement.

Podemos obtener las coordenadas relativas a la ventana de todo el documento como document.documentElement.getBoundingClientRect(), la propiedad bottom será la coordenada relativa a la ventana del fondo del documento.

Por ejemplo, si la altura de todo el documento es 2000px, entonces:

// cuando estamos en la parte superior de la página
//  window-relative top = 0    (relativo a la ventana,  límite superior = 0 )
document.documentElement.getBoundingClientRect().top = 0

// window-relative bottom = 2000    (relativo a la ventana, límite inferior = 2000)
// el documento es largo, así que probablemente esté más allá del fondo de la ventana
document.documentElement.getBoundingClientRect().bottom = 2000

Si nos desplazamos 500px abajo, entonces:

// la parte superior del documento está 500px por encima de la ventana
document.documentElement.getBoundingClientRect().top = -500
// la parte inferior del documento está 500px más cerca
document.documentElement.getBoundingClientRect().bottom = 1500

Cuando nos desplazamos hasta el final, asumiendo que la altura de la venta es 600px:

// La parte superior del documento está 1400px sobre la ventana
document.documentElement.getBoundingClientRect().top = -1400
// la parte inferior del documento está a 600px debajo de la ventana
document.documentElement.getBoundingClientRect().bottom = 600

Tened en cuenta que el fondo del documento bottom nunca puede ser 0, porque nunca llega a la parte superior de la ventana. El límite más bajo de la coordenada bottom es la altura de la ventana (asumimos que es 600), no podemos desplazarla más hacia arriba.

Podemos obtener la altura de la ventana con document.documentElement.clientHeight.

Para nuestra tarea, necesitamos saber cuando tenemos el final del documento a unos 100px (esto es: 600-700px, si la altura es de 600).

Así que aquí está la función:

function populate() {
  while(true)
  {
    // final del documento
    let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;

    // si el usuario no se ha desplazado lo suficiente (> 100px hasta el final)
    if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;
      // vamos añadir más datos
      document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
  }
}

Abrir la solución en un entorno controlado.

importancia: 5

Crea un botón “ir arriba” para ayudar con el desplazamiento de la página.

Debería funcionar así:

  • Mientras que la página no se desplace hacia abajo al menos la altura de la ventana… es invisible.
  • Cuando la página se desplaza hacia abajo más que la altura de la ventana – aparece una flecha “hacia arriba” en la esquina superior izquierda. Si la página se desplaza hacia atrás desaparece.
  • Cuando se hace click en la flecha, la página se desplaza hacia arriba hasta el tope.

Así (esquina superior izquierda, desplácese para ver):

Abrir un entorno controlado para la tarea.

importancia: 4

Digamos que tenemos un cliente con baja velocidad de conexión y queremos cuidar su tarifa de datos.

Para ello decidimos no mostrar las imágenes inmediatamente, sino sustituirlas por marcadores de posición, como este:

<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">

Así que, inicialmente todas las imágenes son placeholder.svg. Cuando la página se desplaza a la posición donde el usuario puede ver la imagen – cambiamos src a data-src, y así la imagen se carga.

Aquí hay un ejemplo en iframe:

Desplázate para ver las imágenes cargadas “bajo demanda”.

Requerimientos:

  • Cuando la página se carga, las imágenes que están en pantalla deben cargarse inmediatamente, antes de cualquier desplazamiento.
  • Algunas imágenes pueden ser regulares, sin data-src. El código no debe tocarlas.
  • Una vez que una imagen se carga, no debe recargarse más cuando haya desplazamiento arriba/abajo.

P.D. Si puedes, haz una solución más avanzada para “precargar” las imágenes que están más abajo/después de la posición actual.

Post P.D. Sólo se debe manejar el desplazamiento vertical, no el horizontal.

Abrir un entorno controlado para la tarea.

El manejador onscroll debería comprobar qué imágenes son visibles y mostrarlas.

También queremos que se ejecute cuando se cargue la página, para detectar las imágenes visibles inmediatamente y cargarlas.

El código debería ejecutarse cuando se cargue el documento, para que tenga acceso a su contenido.

O ponerlo en la parte inferior del <body>:

// ...el contenido de la página está arriba...

function isVisible(elem) {

  let coords = elem.getBoundingClientRect();

  let windowHeight = document.documentElement.clientHeight;

  // ¿El borde superior del elemento es visible?
  let topVisible = coords.top > 0 && coords.top < windowHeight;

  // ¿El borde inferior del elemento es visible?
  let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

La función showVisible() utiliza el control de visibilidad, implementado por isVisible(), para cargar imágenes visibles:

function showVisible() {
  for (let img of document.querySelectorAll('img')) {
    let realSrc = img.dataset.src;
    if (!realSrc) continue;

    if (isVisible(img)) {
      img.src = realSrc;
      img.dataset.src = '';
    }
  }
}

showVisible();
window.onscroll = showVisible;

P.D. La solución tiene una variante de isVisible que “precarga” imágenes que están dentro de 1 página por encima/debajo del desplazamiento del documento actual.

Abrir la solución en un entorno controlado.

Mapa del Tutorial