Come creare sezioni di scorrimento a scatto con CSS Scroll-Snap (alternativa fullpage.js)

Pubblicato: 2022-07-19

In questo tutorial creeremo una pagina che scatta da una sezione a schermo intero all'altra mentre l'utente scorre. Questo effetto è stato reso popolare dalla libreria fullpage.js . Ma ora ci sono opzioni migliori a causa delle modifiche alla licenza a pagina intera (ora devi pagare per questo), il nuovo modulo CSS scroll-snap e il supporto completo del browser dell'API dell'osservatore dell'intersezione.

Quindi, se stai cercando un'alternativa fullpage.js, potresti non aver nemmeno bisogno di un'intera libreria, puoi semplicemente codificarla tu stesso!

In effetti, l'effetto di snap è al 100% CSS. JS viene utilizzato solo per sfumare gli elementi quando lo schermo "si aggancia" alla vista.

Utilizzeremo questo "Dinosaur Park scroll snap demo" di Michelle Barker disponibile su CodePen come fonte di ispirazione:

https://codepen.io/michellebarker/pen/PowYKXJ Guarda la demo a scorrimento di Pen Dinosaur Park di Michelle Barker (@michellebarker) su CodePen.

Attenzione, probabilmente vorrai vederlo su uno schermo più grande per sperimentare appieno l'effetto "scroll snap".

Usando CSS insieme a Intersection Observer, faremo scorrere ogni sezione a schermo intero della pagina e dissolveremo il contenuto quando entra nel viewport.

Ancora meglio, sono solo circa 30 righe di codice JS! Le animazioni sono fatte con CSS; tutto ciò che dobbiamo fare è capire quando sezioni e contenuti entrano nel nostro viewport con JS.

1) Costruisci la tua pagina

Innanzitutto, sarà necessario creare una pagina o configurarne una esistente in modo che sia compatibile con questo semplice effetto. Ci sono due cose da notare qui:

Stiamo usando un elemento <main> , che contiene le nostre sezioni. Questo elemento principale è 100vh, così come ciascuno degli elementi <section> all'interno.

HTML:

<main> <section class="section section-1"> <div class="section__content" data-content >Contenuto all'interno</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Contenuto all'interno</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Esplora e scopri</h3 > </header> <div class="section__content" data-content >Contenuto all'interno</div> </section> </main>

CSS:

/* Comportamento di scorrimento */ @media (altezza minima: 30 em) { main { scroll-snap-type: y obbligatorio; altezza: 100vh; overflow-y: scorrere; } } .sezione { colore: bianco; posizione: relativa; scroll-snap-align: centro; display: flessibile; direzione flessibile: colonna; altezza minima: 100vh; } @media (altezza minima: 30 em) { .sezione { altezza: 100 vh; } }

2) Configura lo snapping con CSS

immagine-16-11

Qui possiamo vedere che ci sono più sezioni, ognuna con un'altezza di 100vh.

Anche l'elemento <main> è 100vh, con overflow-y:scroll.

Per l'utente, il comportamento di scorrimento è lo stesso di una pagina Web predefinita.

Se hai aggiunto il CSS menzionato sopra, l'effetto snap sarà già in gioco. Diamo un'occhiata a come funziona.

Innanzitutto, la query " @media (min-height: 30em) " disabilita l'effetto di snap per le dimensioni dello schermo dei dispositivi mobili che sono troppo brevi in ​​termini di altezza. Sotto la sezione principale, c'è una proprietà che abilita lo snap:

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

Questa è una piccola proprietà interessante "imposta il modo in cui i punti di snap vengono applicati rigorosamente sul contenitore di scorrimento nel caso ce ne sia uno" (MDN).

E poi nelle nostre sezioni abbiamo:

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

Questa proprietà "proprietà specifica la posizione di snap della scatola come allineamento della sua area di snap (come oggetto di allineamento) all'interno dello snapport del relativo contenitore di snap (come contenitore di allineamento)" (MDN).

Scopri di più sul modulo CSS scroll-snap qui:

Ed è così semplice. I bambini diretti all'interno del contenitore <main> (tutte le sezioni), scorreranno lo snap al centro del contenitore <main>. Poiché sia ​​il Main che la Section sono 100vh, lo scorrimento scatterà da una sezione all'altra.

3) Dissolvenza del contenuto nell'utilizzo di Intersection Observer

Ormai abbiamo un effetto di scorrimento della pagina intera e, se non vuoi fare nient'altro, puoi saltare questa sezione e goderti il ​​tuo sito web. Tuttavia, quando ogni sezione di pagina intera viene visualizzata, voglio sfumare il contenuto all'interno: un effetto unico e interessante (anche possibile con fullpage.js).

Per fare ciò, utilizzeremo l'osservatore di intersezione per comprendere il posizionamento delle sezioni all'interno della nostra vista <main>.

sezioni const = [...document.querySelectorAll("sezione")]; let options = { rootMargin: "0px", soglia: 0,75, }; const callback = (voci, osservatore) => { voci.forEach((voce) => { const { target } = voce; if (entry.intersectionRatio >= 0.75) { target.classList.add("è-visibile") ; } else { target.classList.remove ("è visibile"); } }); }; const osservatore = new IntersectionObserver(callback, opzioni); sezioni.forEach((sezione, indice) => { sezione constChildren = [...section.querySelector("[contenuto-dati]").figli]; sezioneChildren.forEach((el, indice) => { el.style .setProperty("--delay", `${index * 250}ms`); });observer.observe(sezione); });

Ci sono due cose che vengono fatte qui. Innanzitutto, identifica quando una sezione è nel viewport e, quando entra, aggiunge una classe CSS .is-visible . Quando esce dal viewport, rimuove quella classe.

Inoltre, quando questa sezione entra nel viewport, imposta consecutivamente (una dopo l'altra) la proprietà di ritardo per 250 ms su ciascuno degli elementi figli. Questo crea un effetto di dissolvenza sfalsato.

Lo fa solo ai bambini all'interno di elementi che hanno l'attributo di contenuto di dati. Quindi devi aggiungerlo ai wrapper attorno al contenuto delle tue pagine se vuoi che la dissolvenza abbia effetto.

Ora, per farlo funzionare, dobbiamo impostare l'animazione di dissolvenza in entrata per gli elementi a cui è stata aggiunta la classe .is-visible.

@media (altezza minima: 30 em) { .section__content > * { opacità: 0; trasformare: translate3d(0, 4rem, 0); transizione: opacità 800 ms var(--delay), trasforma 800 ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacità: 1; trasformare: translate3d(0, 1rem, 0); } .è-visibile .section__img { opacità: 0,75; }

Se ci riferiamo all'HTML dalla demo iniziale, vedrai che c'è un div che avvolge il contenuto con la classe di .section__content e l'attributo data-content.

<main> <section class="section section-1"> <div class="section__content" data-content >Contenuto all'interno</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Contenuto all'interno</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Esplora e scopri</h3 > </header> <div class="section__content" data-content >Contenuto all'interno</div> </section> </main>

Questo lega insieme il nostro JS e CSS. L'opacità è 0 per il contenuto fino a quando la classe .is-visible non viene aggiunta dall'osservatore di intersezione quando entra nel viewport. Quando esce, torna a un'opacità di 0, quindi indipendentemente dalla direzione di scorrimento ci sarà sempre un feed attivo.

Infine, il delay che viene applicato consecutivamente a ciascun elemento figlio fa sfalsare la dissolvenza in atto.

Nota la terza sezione. L'intestazione della sezione non è all'interno di una sezione del contenuto dei dati, quindi non svanirà (sarà già lì).

Tutto il codice

Ecco la demo:

isotropico-2022-07-15-at-15-00-58

Ecco tutto il codice che abbiamo utilizzato nella nostra demo:

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>Contenuto all'interno</h2> <p>bla bla bla</p> </div> < /section> <section class="section section-2"> <div class="section__content" data-content> <h2>Contenuto all'interno</h2> <p>bla bla bla</p> </div> </ section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Esplora e scopri</h3> </header> <div class="section__content" data-content > <h2>Contenuto all'interno</h2> <p>bla bla bla</p> </div> </section> </main>

CSS

@media (altezza minima: 30 em) { main { scroll-snap-type: y obbligatorio; altezza: 100vh; overflow-y: scorrere; } } .sezione { colore: bianco; posizione: relativa; scroll-snap-align: centro; display: flessibile; direzione flessibile: colonna; altezza minima: 100vh; } @media (altezza minima: 30 em) { .sezione { altezza: 100 vh; } } @media (altezza minima: 30 em) { .section__content > * { opacità: 0; trasformare: translate3d(0, 4rem, 0); transizione: opacità 800 ms var(--delay), trasforma 800 ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacità: 1; trasformare: translate3d(0, 1rem, 0); } .è-visibile .section__img { opacità: 0,75; }

JS

sezioni const = [...document.querySelectorAll("sezione")]; let options = { rootMargin: "0px", soglia: 0,75, }; const callback = (voci, osservatore) => { voci.forEach((voce) => { const { target } = voce; if (entry.intersectionRatio >= 0.75) { target.classList.add("è-visibile") ; } else { target.classList.remove ("è visibile"); } }); }; const osservatore = new IntersectionObserver(callback, opzioni); sezioni.forEach((sezione, indice) => { sezione constChildren = [...section.querySelector("[contenuto di dati]").figli]; sezioneChildren.forEach((el, indice) => { el.style .setProperty("--delay", `${index * 250}ms`); });observer.observe(sezione); });

Conclusione

Questa è l'alternativa perfetta a fullpage.js che non si limita a scattare tra le sezioni a schermo intero. Abbiamo anche utilizzato l'API di osservazione dell'intersezione per capire quando una sezione entra nella pagina e quindi applicare dinamicamente un'animazione sfalsata. Puoi utilizzare questo esempio di base per creare e creare effetti davvero interessanti con JS e CSS vanigliati minimi.