Jak tworzyć przyciągające sekcje przewijania za pomocą CSS Scroll-Snap (alternatywa fullpage.js)

Opublikowany: 2022-07-19

W tym samouczku stworzymy stronę, która będzie przeskakiwać z jednej sekcji pełnoekranowej do drugiej podczas przewijania przez użytkownika. Efekt ten spopularyzowała biblioteka fullpage.js . Ale teraz są lepsze opcje ze względu na zmiany licencji na fullpage (teraz trzeba za to zapłacić), nowy moduł CSS scroll-snap i pełną obsługę przeglądarki API obserwatora skrzyżowania.

Tak więc, jeśli szukasz alternatywy fullpage.js, możesz nawet nie potrzebować całej biblioteki, możesz po prostu sam ją zakodować!

W rzeczywistości efekt przyciągania to 100% CSS. JS służy tylko do zanikania elementów, gdy ekran „wskakuje” do widoku.

Dla inspiracji wykorzystamy to „demo zwoju zwoju w Parku Dinozaurów” autorstwa Michelle Barker dostępne na CodePen:

https://codepen.io/michellebarker/pen/PowYKXJ Zobacz demonstrację przewijania Pen Dinosaur Park autorstwa Michelle Barker (@michellebarker) na CodePen.

Uwaga, prawdopodobnie będziesz chciał zobaczyć to na większym ekranie, aby w pełni doświadczyć efektu „przewijania”.

Używając CSS w połączeniu z Intersection Observer, sprawimy, że każda pełnoekranowa sekcja strony będzie się przewijać i zanikać, gdy wejdzie ona do okienka ekranu.

Co więcej, to tylko ~30 linijek kodu JS! Animacje są wykonywane za pomocą CSS; wszystko, co musimy zrobić, to zrozumieć, kiedy sekcje i treść wchodzą do naszego widoku z JS.

1) Zbuduj swoją stronę

Najpierw trzeba zbudować stronę lub skonfigurować istniejącą, aby była zgodna z tym prostym efektem. Należy zwrócić uwagę na dwie rzeczy:

Używamy elementu <main> , który zawiera nasze sekcje. Ten główny element to 100vh, podobnie jak każdy z elementów <section> .

HTML:

<main> <section class="section section-1"> <div class="section__content" data-content >Zawartość wewnątrz</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Treść wewnątrz</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Odkrywać i odkrywać</h3 > </header> <div class="section__content" data-content >Zawartość wewnątrz</div> </section> </main>

CSS:

/* Zachowanie przewijania */ @media (min-height: 30em) { main { scroll-snap-type: y obowiązkowe; wysokość: 100vh; overflow-y: przewijanie; } } .sekcja { kolor: biały; pozycja: względna; scroll-snap-align: środek; wyświetlacz: elastyczny; kierunek ugięcia: kolumna; wysokość min: 100vh; } @media (min-wysokość: 30em) { .section {wysokość: 100vh; } }

2) Skonfiguruj przyciąganie za pomocą CSS

obraz-16-11

Tutaj widzimy, że istnieje wiele sekcji, każda o wysokości 100vh.

Element <main> to również 100vh, z overflow-y:scroll.

Dla użytkownika zachowanie przewijania jest takie samo, jak w przypadku domyślnej strony internetowej.

Jeśli dodałeś wspomniany CSS, efekt przyciągania będzie już aktywny. Zobaczmy, jak to działa.

Po pierwsze, zapytanie „ @media (min-height: 30em) ” wyłącza efekt przyciągania w przypadku zbyt krótkich rozmiarów ekranu urządzeń przenośnych. W sekcji głównej znajduje się jedna właściwość, która umożliwia przyciąganie:

main { .... scroll-snap-type: y obowiązkowe; .... }

Jest to fajna mała właściwość „określa, jak ściśle punkty przyciągania są wymuszane w kontenerze przewijania, jeśli taki istnieje” (MDN).

A następnie w naszych sekcjach mamy:

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

Ta właściwość „właściwość określa położenie przyciągania pudełka jako wyrównanie jego obszaru przyciągania (jako temat wyrównania) w obrębie portu przyciągania jego kontenera przyciągania (jako kontenera wyrównania)” (MDN).

Dowiedz się więcej o module CSS scroll-snap tutaj:

I to takie proste. Bezpośrednie dzieci w kontenerze <main> (wszystkie sekcje) zostaną przewinięte do środka kontenera <main>. Ponieważ zarówno Main, jak i Section mają 100vh, przewijanie będzie przeskakiwać z sekcji na sekcję.

3) Zanikanie treści podczas korzystania z obserwatora skrzyżowań

Do tej pory mamy efekt przewijania całej strony, a jeśli nie chcesz robić nic więcej, możesz pominąć tę sekcję i cieszyć się swoją witryną. Jednak, gdy w widoku pojawia się każda pełna sekcja strony, chcę zaciemnić zawartość - unikalny i fajny efekt (również taki, który jest możliwy dzięki fullpage.js).

Aby to zrobić, użyjemy obserwatora skrzyżowania, aby zrozumieć położenie sekcji w naszym oknie roboczym <main>.

const section = [...document.querySelectorAll("sekcja"]); let options = { rootMargin: "0px", próg: 0,75, }; const callback = (entries, Observer) => { entry.forEach((entry) => { const { target } = entry; if (entry.intersectionRatio >= 0,75) { target.classList.add("is-visible") } else { target.classList.remove("jest-widoczny"); } }); }; const obserwator = new IntersectionObserver(callback, options); section.forEach((sekcja, indeks) => { const sectionChildren = [...section.querySelector("[zawartość-danych]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); }); obserwator.observe(sekcja); });

Robi się tu dwie rzeczy. Po pierwsze, identyfikuje, kiedy sekcja znajduje się w rzutni, a gdy wchodzi, dodaje klasę CSS .is-visible . Gdy opuszcza rzutnię, usuwa tę klasę.

Dodatkowo, gdy ta sekcja wchodzi do rzutni, kolejno (jeden po drugim) ustawia właściwość opóźnienia na 250ms na każdym z elementów potomnych. Daje to efekt rozłożonego zanikania.

Robi to tylko dzieciom w elementach, które mają atrybut zawartości danych. Musisz więc dodać to do otoczek wokół zawartości stron, jeśli chcesz, aby efekt zanikał.

Teraz, aby to zadziałało, musimy skonfigurować animację pojawiania się elementów, które mają dodaną klasę .is-visible.

@media (min-wysokość: 30em) { .section__content > * { krycie: 0; transformacja: translate3d(0, 4rem, 0); przejście: opacity 800ms var(--delay), transform 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacity: 1; transformacja: translate3d(0, 1rem, 0); } .jest widoczny .sekcja__img { krycie: 0,75; }

Jeśli odwołamy się do HTML od początku demonstracji, zobaczysz, że istnieje div owijający zawartość z klasą .section__content i atrybutem data-content .

<main> <section class="section section-1"> <div class="section__content" data-content >Zawartość wewnątrz</div> </section> <section class="section section-2"> <div class= "section__content" data-content >Treść wewnątrz</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Odkrywać i odkrywać</h3 > </header> <div class="section__content" data-content >Zawartość wewnątrz</div> </section> </main>

To spaja nasz JS i CSS. Przezroczystość wynosi 0 dla treści, dopóki klasa .is-visible nie zostanie dodana przez obserwatora skrzyżowania, gdy wejdzie ona do rzutni. Kiedy wychodzi, powraca do krycia 0, więc niezależnie od kierunku przewijania zawsze będzie aktywny kanał.

Wreszcie delay , które jest stosowane kolejno do każdego elementu podrzędnego, powoduje rozłożenie efektu zanikania.

Zwróć uwagę na trzecią sekcję. Nagłówek sekcji nie znajduje się w sekcji zawartości danych, więc nie zanika (już tam będzie).

Cały kod

Oto demo:

izotropowy-2022-07-15-at-15-00-58

Oto cały kod, którego użyliśmy w naszym demo:

HTML

<main> <section class="sekcja sekcja-1"> <div class="section__content" zawartość danych> <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>Zawartość wewnątrz</h2> <p>bla bla bla</p> </div> < /section> <section class="section section-2"> <div class="section__content" data-content> <h2>Zawartość wewnątrz</h2> <p>bla bla bla</p> </div> </ section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">Eksploruj i odkrywaj</h3> </header> <div class="section__content" zawartość danych > <h2>Zawartość wewnątrz</h2> <p>bla bla bla</p> </div> </section> </main>

CSS

@media (min-height: 30em) { main { scroll-snap-type: y obowiązkowe; wysokość: 100vh; przepełnienie-y: przewijanie; } } .sekcja { kolor: biały; pozycja: względna; scroll-snap-align: środek; wyświetlacz: elastyczny; kierunek ugięcia: kolumna; wysokość min: 100vh; } @media (min-wysokość: 30em) { .section {wysokość: 100vh; } } @media (min-wysokość: 30em) { .section__content > * { opacity: 0; transformacja: translate3d(0, 4rem, 0); przejście: opacity 800ms var(--delay), transform 800ms cubic-bezier(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { opacity: 1; transformacja: translate3d(0, 1rem, 0); } .is-visible .section__img { krycie: 0,75; }

JS

const section = [...document.querySelectorAll("sekcja"]); let options = { rootMargin: "0px", próg: 0,75, }; const callback = (entries, Observer) => { entry.forEach((entry) => { const { target } = entry; if (entry.intersectionRatio >= 0,75) { target.classList.add("is-visible") } else { target.classList.remove("jest-widoczny"); } }); }; const obserwator = new IntersectionObserver(callback, options); section.forEach((sekcja, indeks) => { const sectionChildren = [...section.querySelector("[zawartość-danych]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); }); obserwator.observe(sekcja); });

Wniosek

Jest to idealna alternatywa fullpage.js, która nie kończy się tylko na przeskakiwaniu między sekcjami pełnoekranowymi. Wykorzystaliśmy również interfejs API obserwatora skrzyżowania, aby zrozumieć, kiedy sekcja wchodzi na stronę, a następnie dynamicznie zastosować animację przesuniętą w czasie. Możesz użyć tego podstawowego przykładu, aby zbudować i stworzyć naprawdę fajne efekty przy minimalnym waniliowym JS i CSS.