Cum să faci apariția secțiunilor de defilare cu CSS Scroll-Snap (alternativă fullpage.js)

Publicat: 2022-07-19

În acest tutorial, vom crea o pagină care trece de la o secțiune pe ecran complet la alta pe măsură ce utilizatorul derulează. Acest efect a fost popularizat de biblioteca fullpage.js . Dar acum, există opțiuni mai bune datorită modificărilor de licențiere la pagina completă (acum trebuie să plătiți pentru aceasta), a noului modul CSS de defilare-snap și a suportului complet pentru browser pentru API-ul de observare a intersecției.

Deci, dacă sunteți în căutarea unei alternative fullpage.js, este posibil să nu aveți nevoie nici măcar de o bibliotecă întreagă, o puteți codifica singur!

De fapt, efectul de snapping este 100% CSS. JS este folosit doar pentru a estompa elementele atunci când ecranul „se afișează” la vedere.

Vom folosi această „Demo pentru defilare din Dinosaur Park” de Michelle Barker, disponibilă pe CodePen pentru inspirație:

https://codepen.io/michellebarker/pen/PowYKXJ Vedeți demo-ul de defilare din Pen Dinosaur Park de Michelle Barker (@michellebarker) pe CodePen.

Atenție, probabil că veți dori să vedeți acest lucru pe un ecran mai mare pentru a experimenta pe deplin efectul de „scroll snap”.

Folosind CSS cuplat cu Intersection Observer, vom face ca fiecare secțiune de ecran complet a paginii să deruleze rapid și să facem estomparea conținutului când intră în fereastra de vizualizare.

Și mai bine, este doar ~ 30 de linii de cod JS! Animațiile se fac cu CSS; tot ce trebuie să facem este să înțelegem când secțiunile și conținutul intră în fereastra noastră de vizualizare cu JS.

1) Construiește-ți pagina

În primul rând, va trebui să construiți o pagină sau să configurați una existentă pentru a fi compatibilă cu acest efect simplu. Sunt două lucruri de remarcat aici:

Folosim un element <main> , care conține secțiunile noastre. Acest element principal este 100vh, la fel ca fiecare dintre elementele <section> din interior.

HTML:

<main> <section class="section section-1"> <div class="section__content" data-content >Conținut în interior</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Conținut în interior</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorați și descoperiți</h3 > </header> <div class="section__content" data-content >Conținut în interior</div> </section> </main>

CSS:

/* Comportamentul derulării */ @media (înălțime minimă: 30em) { principal { tip de defilare: y obligatoriu; inaltime: 100vh; overflow-y: scroll; } } .sectiune { culoare: alb; poziție: relativă; scroll-snap-align: centru; display: flex; flex-direcție: coloană; inaltime minima: 100vh; } @media (min-height: 30em) { .section { inaltime: 100vh; } }

2) Configurați Snapping cu CSS

imaginea-16-11

Aici putem observa că există mai multe secțiuni, fiecare cu o înălțime de 100vh.

Elementul <principal>, este de asemenea 100vh, cu overflow-y:scroll.

Pentru utilizator, comportamentul de defilare este același cu o pagină web implicită.

Dacă ați adăugat CSS-ul menționat mai sus, efectul de snapping va fi deja în joc. Să aruncăm o privire la cum funcționează.

În primul rând, interogarea „ @media (min-height: 30em) ” dezactivează efectul de fixare pentru dimensiunile ecranului mobil care sunt prea scurte în ceea ce privește înălțimea. Sub secțiunea principală, există o proprietate care permite aprinderea:

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

Aceasta este o mică proprietate grozavă „setează cât de strict sunt aplicate punctele de fixare pe containerul de defilare în cazul în care există unul” (MDN).

Și apoi, în secțiunile noastre, avem:

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

Această proprietate „proprietate specifică poziția de snap a casetei ca o aliniere a zonei de snap (ca subiect de aliniere) în snapport-ul containerului său de snap (ca container de aliniere)” (MDN).

Aflați mai multe despre modulul CSS scroll-snap aici:

Și este la fel de simplu. Copiii direcționați în containerul <principal> (toate secțiunile), vor derula-snapasă în centrul containerului <principal>. Deoarece atât Principalul, cât și Secțiunea sunt 100vh, defilarea se va face de la secțiune la secțiune.

3) Fade Content In Utilizând Intersection Observer

Până acum, avem un efect de defilare a întregii pagini, iar dacă nu doriți să faceți altceva, puteți sări peste această secțiune și să vă bucurați de site-ul dvs. Cu toate acestea, atunci când fiecare secțiune de pagină completă apare în vizualizare, vreau să atenuez conținutul din interior - un efect unic și cool (de asemenea, unul care este posibil cu fullpage.js).

Pentru a face acest lucru, vom folosi observatorul de intersecție pentru a înțelege poziționarea secțiunilor în portul nostru de vizualizare <principal>.

const sections = [...document.querySelectorAll("sectiune"]); let options = { rootMargin: "0px", threshold: 0.75, }; const callback = (intrari, observator) => { entries.forEach((entry) => { const { target } = intrare; if (entry.intersectionRatio >= 0,75) { target.classList.add("este-vizibil") ; } else { target.classList.remove("este-vizibil"); } }); }; const observer = new IntersectionObserver (callback, opțiuni); sections.forEach((section, index) => { const sectionChildren = [...section.querySelector("[data-content]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); }); observer.observe(secțiune); });

Sunt două lucruri care se fac aici. În primul rând, identifică când o secțiune este în fereastra de vizualizare și, pe măsură ce intră, adaugă o clasă CSS .is-visible . Pe măsură ce părăsește fereastra, elimină acea clasă.

În plus, pe măsură ce această secțiune intră în fereastra de vizualizare, aceasta setează consecutiv (unul după altul) proprietatea de întârziere pentru 250 ms pentru fiecare dintre elementele secundare. Acest lucru face ca efectul de decolorare eșalonat.

Face acest lucru doar copiilor din elementele care au atributul de conținut de date. Așa că trebuie să adăugați asta la împachetările din jurul conținutului paginilor dvs. dacă doriți ca estomparea să aibă efect.

Acum, pentru a face acest lucru, trebuie să setăm animația de fade-in pentru elementele cărora li se adaugă clasa .is-visible.

@media (înălțime minimă: 30em) { .section__content > * { opacitate: 0; transform: translate3d(0, 4rem, 0); tranziție: opacitate 800ms var(--delay), transform 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .este-vizibil .section__content > * { opacitate: 1; transform: translate3d(0, 1rem, 0); } .este-vizibil .section__img { opacitate: 0,75; }

Dacă ne referim la HTML de la demonstrația de la început, veți vedea că există un div care cuprinde conținutul cu clasa .section__content și atributul data-content.

<main> <section class="section section-1"> <div class="section__content" data-content >Conținut în interior</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Conținut în interior</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorați și descoperiți</h3 > </header> <div class="section__content" data-content >Conținut în interior</div> </section> </main>

Acest lucru leagă JS-ul și CSS-ul nostru împreună. Opacitatea este 0 pentru conținut până când clasa .is-visible este adăugată de observatorul de intersecție când intră în fereastra de vizualizare. Când pleacă, revine la o opacitate de 0, așa că, indiferent de direcția de defilare, va exista întotdeauna un flux în vigoare.

În cele din urmă, delay care este aplicată consecutiv fiecărui element copil eșalonează efectul de estompare.

Observați a treia secțiune. Antetul secțiunii nu se află într-o secțiune de conținut de date, așa că nu se va estompa (va fi deja acolo).

Tot Codul

Iată demonstrația:

izotrop-2022-07-15-la-15-00-58

Iată tot codul pe care l-am folosit în demonstrația noastră:

HTML

<principal> <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>Conținut în interior</h2> <p>bla bla bla</p> </div> < /section> <section class="section section-2"> <div class="section__content" data-content> <h2>Conținut în interior</h2> <p>bla bla bla</p> </div> </ section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Explorați și descoperiți</h3> </header> <div class="section__content" conținut de date > <h2>Conținut din interior</h2> <p>bla bla bla</p> </div> </section> </main>

CSS

@media (min-height: 30em) { main { scroll-snap-type: y obligatoriu; inaltime: 100vh; overflow-y: scroll; } } .sectiune { culoare: alb; poziție: relativă; scroll-snap-align: centru; display: flex; flex-direcție: coloană; inaltime minima: 100vh; } @media (min-height: 30em) { .section { inaltime: 100vh; } } @media (înălțime minimă: 30em) { .section__content > * { opacitate: 0; transform: translate3d(0, 4rem, 0); tranziție: opacitate 800ms var(--delay), transform 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .este-vizibil .section__content > * { opacitate: 1; transform: translate3d(0, 1rem, 0); } .este-vizibil .section__img { opacitate: 0,75; }

JS

const sections = [...document.querySelectorAll("sectiune"]); let options = { rootMargin: "0px", threshold: 0.75, }; const callback = (intrari, observator) => { entries.forEach((entry) => { const { target } = intrare; if (entry.intersectionRatio >= 0,75) { target.classList.add("este-vizibil") ; } else { target.classList.remove("este-vizibil"); } }); }; const observer = new IntersectionObserver (callback, opțiuni); sections.forEach((section, index) => { const sectionChildren = [...section.querySelector("[data-content]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); }); observer.observe(secțiune); });

Concluzie

Aceasta este alternativa perfectă fullpage.js, care nu se oprește doar la apariția între secțiunile de ecran complet. De asemenea, am folosit API-ul observator de intersecție pentru a înțelege când o secțiune intră în pagină și apoi aplicăm dinamic o animație eșalonată. Puteți folosi acest exemplu de bază pentru a construi și a realiza niște efecte cu adevărat interesante cu JS și CSS minim vanilie.