Cómo hacer secciones de desplazamiento de ajuste con CSS Scroll-Snap (alternativa fullpage.js)

Publicado: 2022-07-19

En este tutorial, vamos a crear una página que salte de una sección de pantalla completa a otra a medida que el usuario se desplaza. Este efecto fue popularizado por la biblioteca fullpage.js . Pero ahora, hay mejores opciones debido a los cambios de licencia a la página completa (ahora debe pagar por ella), el nuevo módulo CSS scroll-snap y el soporte completo del navegador de la API del observador de intersección.

Entonces, si está buscando una alternativa fullpage.js, es posible que ni siquiera necesite una biblioteca completa, ¡simplemente puede codificarla usted mismo!

De hecho, el efecto de ajuste es 100% CSS. JS solo se usa para desvanecer elementos cuando la pantalla "se ajusta" a la vista.

Haremos uso de esta "demostración de complemento de desplazamiento de Dinosaur Park" de Michelle Barker disponible en CodePen para inspirarnos:

https://codepen.io/michellebarker/pen/PowYKXJ Vea la demostración de desplazamiento rápido de Pen Dinosaur Park por Michelle Barker (@michellebarker) en CodePen.

Atención, probablemente querrá ver esto en una pantalla más grande para experimentar completamente el efecto de "desplazamiento instantáneo".

Al usar CSS junto con Intersection Observer, haremos que cada sección de pantalla completa de la página se desplace rápidamente y el contenido se desvanezca cuando ingrese a la ventana gráfica.

Aún mejor, ¡son solo ~ 30 líneas de código JS! Las animaciones están hechas con CSS; todo lo que tenemos que hacer es entender cuándo las secciones y el contenido ingresan a nuestra ventana gráfica con JS.

1) Crea tu página

Primero, deberá crear una página o configurar una existente para que sea compatible con este simple efecto. Hay dos cosas a tener en cuenta aquí:

Estamos usando un elemento <main> , que contiene nuestras secciones. Este elemento principal es 100vh, al igual que cada uno de los elementos <section> dentro.

HTML:

<principal> <sección clase="sección sección-1"> <div clase="sección__contenido" datos-contenido >Contenido dentro</div> </sección> <sección clase="sección sección-2"> <div clase= "section__content" data-content >Contenido dentro</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorar y descubrir</h3 > </header> <div class="section__content" data-content >Contenido dentro</div> </section> </main>

CSS:

/* Comportamiento de desplazamiento */ @media (min-height: 30em) { main { scroll-snap-type: y obligatorio; altura: 100vh; desbordamiento-y: desplazamiento; } } .sección { color: blanco; posición: relativa; desplazar-ajustar-alinear: centro; pantalla: flexible; dirección de flexión: columna; min-altura: 100vh; } @media (altura mínima: 30em) { .sección { altura: 100vh; } }

2) Configurar ajuste con CSS

imagen-16-11

Aquí podemos ver que hay varias secciones, cada una con una altura de 100vh.

El elemento <main> también es 100vh, con overflow-y:scroll.

Para el usuario, el comportamiento de desplazamiento es el mismo que el de una página web predeterminada.

Si agregó el CSS mencionado anteriormente, el efecto de ajuste ya estará en juego. Echemos un vistazo a cómo funciona.

Primero, la consulta " @media (min-height: 30em) " desactiva el efecto de ajuste para los tamaños de pantalla móviles que son demasiado cortos en términos de altura. Debajo de la sección principal, hay una propiedad que habilita el ajuste:

main { .... scroll-snap-type: y obligatorio; .... }

Esta es una pequeña propiedad genial que "establece cuán estrictamente se aplican los puntos de ajuste en el contenedor de desplazamiento en caso de que haya uno" (MDN).

Y luego, en nuestras secciones, tenemos:

.section { .... scroll-snap-align: centro; .... }

Esta propiedad "especifica la posición de ajuste del cuadro como una alineación de su área de ajuste (como sujeto de alineación) dentro del puerto de ajuste de su contenedor de ajuste (como contenedor de alineación)" (MDN).

Obtenga más información sobre el módulo CSS scroll-snap aquí:

Y es tan simple como eso. Los niños directos dentro del contenedor <principal> (todas las secciones), se desplazarán al centro del contenedor <principal>. Debido a que tanto el Principal como la Sección son 100vh, el desplazamiento se ajustará de una sección a otra.

3) Desvanecer el contenido al usar Intersection Observer

Por ahora, tenemos un efecto de desplazamiento de página completa y, si no desea hacer nada más, puede omitir esta sección y disfrutar de su sitio web. Sin embargo, cuando cada sección de página completa aparece a la vista, quiero que el contenido se desvanezca: un efecto único y genial (también posible con fullpage.js).

Para hacer esto, usaremos el observador de intersección para comprender el posicionamiento de las secciones dentro de nuestra ventana gráfica <principal>.

const secciones = [...document.querySelectorAll("sección")]; let options = { rootMargin: "0px", umbral: 0.75, }; devolución de llamada const = (entradas, observador) => { entradas.forEach((entrada) => { const { objetivo } = entrada; if (entrada.intersectionRatio >= 0.75) { target.classList.add("is-visible") ; } else { target.classList.remove("is-visible"); } }); }; const observador = new IntersectionObserver(devolución de llamada, opciones); secciones.forEach((sección, índice) => { const secciónNiños = [...sección.querySelector("[contenido de datos]").niños]; secciónNiños.paraCada((el, índice) => { el.estilo .setProperty("--delay", `${index * 250}ms`); }); observador.observar(sección); });

Aquí se están haciendo dos cosas. Primero, identifica cuándo una sección está en la ventana gráfica y, cuando ingresa, agrega una clase CSS .is-visible . Cuando sale de la ventana gráfica, elimina esa clase.

Además, a medida que esta sección ingresa a la ventana gráfica, consecutivamente (uno tras otro) establece la propiedad de retraso durante 250 ms en cada uno de los elementos secundarios. Esto crea un efecto de fundido escalonado.

Solo hace esto a los niños dentro de los elementos que tienen el atributo de contenido de datos. Por lo tanto, debe agregar eso a los envoltorios alrededor del contenido de sus páginas si desea que el efecto se desvanezca.

Ahora, para que esto funcione, debemos configurar la animación de aparición gradual para los elementos que tienen agregada la clase .is-visible.

@media (altura mínima: 30em) { .section__content > * { opacidad: 0; transformar: traducir3d(0, 4rem, 0); transición: opacidad 800ms var(--delay), transformar 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacidad: 1; transformar: traducir3d(0, 1rem, 0); } .is-visible .section__img { opacidad: 0.75; }

Si volvemos a consultar el HTML de la demostración inicial, verá que hay un div que envuelve el contenido con la clase .section__content y el atributo data-content.

<principal> <sección clase="sección sección-1"> <div clase="sección__contenido" datos-contenido >Contenido dentro</div> </sección> <sección clase="sección sección-2"> <div clase= "section__content" data-content >Contenido dentro</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorar y descubrir</h3 > </header> <div class="section__content" data-content >Contenido dentro</div> </section> </main>

Esto une nuestro JS y CSS juntos. La opacidad es 0 para el contenido hasta que el observador de intersección agrega la clase .is-visible cuando ingresa a la ventana gráfica. Cuando se va, vuelve a tener una opacidad de 0, por lo que, independientemente de la dirección de desplazamiento, siempre habrá una fuente activa.

Finalmente, el delay que se aplica consecutivamente a cada elemento secundario escalona el efecto de fundido.

Tenga en cuenta la tercera sección. El encabezado de la sección no está dentro de una sección de contenido de datos, por lo que no aparecerá (ya estará allí).

todo el codigo

Aquí está la demostración:

isotropic-2022-07-15-en-15-00-58

Aquí está todo el código que usamos en nuestra demostración:

HTML

<main> <section class="section section-1"> <div class="section__content" data-content> <img class="section__img section__img--left" src="https://s3-us-west-2 .amazonaws.com/s.cdpn.io/85648/trex.svg" alt="T-rex" /> <h2>Contenido interior</h2> <p>bla, bla, bla</p> </div> < /sección> <sección clase="sección sección-2"> <div clase="sección__contenido" datos-contenido> <h2>Contenido dentro</h2> <p>bla, bla, bla</p> </div> </ section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorar y descubrir</h3> </header> <div class="section__content" contenido de datos > <h2>Contenido dentro</h2> <p>bla, bla, bla</p> </div> </section> </main>

CSS

@media (altura mínima: 30em) { principal { scroll-snap-type: y obligatorio; altura: 100vh; desbordamiento-y: desplazamiento; } } .sección { color: blanco; posición: relativa; desplazar-ajustar-alinear: centro; pantalla: flexible; dirección de flexión: columna; min-altura: 100vh; } @media (altura mínima: 30em) { .sección { altura: 100vh; } } @media (altura mínima: 30em) { .section__content > * { opacidad: 0; transformar: traducir3d(0, 4rem, 0); transición: opacidad 800ms var(--delay), transformar 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacidad: 1; transformar: traducir3d(0, 1rem, 0); } .is-visible .section__img { opacidad: 0.75; }

JS

const secciones = [...document.querySelectorAll("sección")]; let options = { rootMargin: "0px", umbral: 0.75, }; devolución de llamada const = (entradas, observador) => { entradas.forEach((entrada) => { const { objetivo } = entrada; if (entrada.intersectionRatio >= 0.75) { target.classList.add("is-visible") ; } else { target.classList.remove("is-visible"); } }); }; const observador = new IntersectionObserver(devolución de llamada, opciones); secciones.paraCada((sección, índice) => { const secciónNiños = [...sección.querySelector("[contenido de datos]").niños]; secciónNiños.paraCada((el, índice) => { el.estilo .setProperty("--delay", `${index * 250}ms`); }); observador.observar(sección); });

Conclusión

Esta es la alternativa perfecta a fullpage.js que no solo se detiene en el ajuste entre secciones de pantalla completa. También usamos la API del observador de intersección para comprender cuándo una sección ingresa a la página y luego aplicamos dinámicamente una animación escalonada. Puede usar este ejemplo básico para construir y crear algunos efectos realmente geniales con un mínimo de JS y CSS de vainilla.