Navegación activa, suave y pegajosa | Programar Plus

¡Asi como dice el titulo! Aquí hay una barra de navegación lateral que …

  1. Utiliza posicionamiento pegajoso. Permanece en la pantalla cuando puede, pero no se superpondrá al encabezado, pie de página ni hará que ninguno de sus enlaces sea inaccesible.
  2. Se desplaza suavemente a las secciones en las que hace clic.
  3. Activa la navegación actual según la posición de desplazamiento (es una cosa de una sola página).

Vea Pen Sticky, Smooth, Active Nav de Chris Coyier (@chriscoyier) en CodePen.

Pegajoso

Es fácil de tirar position: sticky; top: 0; sobre algo. Pero para que funcione, debe estar dentro de un elemento padre más alto. Entonces, la lista desordenada (<ul>) dentro de la navegación (<nav>) funciona muy bien aquí. Gracias al diseño de cuadrícula CSS, el <nav> es tan alto como el <main> área de contenido. Sin embargo, tenga en cuenta que también tenemos que position: -webkit-sticky; para iOS.

También agregué un número mágico para la consulta de medios verticales para que no se quede de tal manera que no pueda acceder a los elementos de navegación inferiores:

/* Only stick if you can fit */
@media (min-height: 300px) {
  nav ul {
    position: sticky;
    top: 0;
  }
}

Suave

En mi primera oportunidad, pensé en el desplazamiento suave basado en JavaScript. Incluso es nativo en estos días sin necesidad de marcos. Puede apuntar a un elemento y desplazarse suavemente hasta él:

document.querySelector('.hello').scrollIntoView({ 
  behavior: 'smooth' 
});

Llevando eso a un conjunto arbitrario de navegación …

let mainNavLinks = document.querySelectorAll("nav ul li a");

mainNavLinks.forEach(link => {
  link.addEventListener("click", event => {
    event.preventDefault();
    let target = document.querySelector(event.target.hash);
    target.scrollIntoView({
      behavior: "smooth",
      block: "start"
    });
  });
});

Eso es compatible tanto en Chrome como en Firefox, pero no en Edge ni en Safari.

Entonces se me ocurrió, ¡CSS puede hacer esto! Hay un scroll-behavior propiedad y puede ponerlo en el documento para que todo se desplace de esa manera:

html {
  scroll-behavior: smooth;
}

Desde nuestra navegacion <a> Los enlaces son enlaces hash / salto / ancla, eso es literalmente todo lo que necesitamos. Olvídese del JavaScript. Especialmente porque el navegador es compatible con scroll-behavior es igual que la versión “fluida” de .scrollIntoView().

Activo

Esto es un poco más complicado, especialmente porque se trata de una aplicación de desplazamiento de una sola página en lugar de páginas individuales con sus propios documentos separados. Si fueran documentos separados, cambiaríamos una clase activa en algún lugar de la navegación o usaríamos un body.specific_page clase o algo así.

En su lugar, tendremos que mirar la posición de desplazamiento de la página, decidir qué sección está a la vista y marcarla de esa manera. Puede haber algo de fantasía IntersectionObserver manera de manejar esto, pero no pude entenderlo, así que en cambio solo estoy mirando todas las secciones relevantes, haciendo un poco de medición y matemáticas, y decidiendo si el enlace está activo de esa manera.

let mainNavLinks = document.querySelectorAll("nav ul li a");
let mainSections = document.querySelectorAll("main section");

let lastId;
let cur = [];

window.addEventListener("scroll", event => {
  let fromTop = window.scrollY;

  mainNavLinks.forEach(link => {
    let section = document.querySelector(link.hash);

    if (
      section.offsetTop <= fromTop &&
      section.offsetTop + section.offsetHeight > fromTop
    ) {
      link.classList.add("current");
    } else {
      link.classList.remove("current");
    }
  });
});

El controlador de desplazamiento allí debería activar una pequeña bandera de advertencia. Ese es el tipo de cosas que probablemente deberían estrangularse, como si tuviera lodash disponible:

window.addEventListener("scroll", () => {
  _.throttle(doThatStuff, 100);
});

Simplemente no hice eso aquí para mantener la demostración libre de dependencias.

¡Oh! Y en gran medida funciona bien en dispositivos móviles (iOS aquí):

Una plantilla gratuita para las páginas de inicio de la biblioteca de JavaScript

Usé todas estas cosas en esta plantilla que hice y que eres libre de usar para lo que sea.