Zbuduj niestandardowy suwak całej strony za pomocą CSS i JavaScript
Opublikowany: 2022-03-11Dużo pracuję z niestandardowymi układami pełnoekranowymi, praktycznie na co dzień. Zazwyczaj te układy implikują znaczną ilość interakcji i animacji. Niezależnie od tego, czy jest to złożona oś czasu przejść wyzwalana czasem, czy też zestaw zdarzeń zależny od użytkownika, w większości przypadków interfejs użytkownika wymaga czegoś więcej niż tylko użycia gotowego rozwiązania w postaci wtyczki z kilkoma poprawkami i zmianami . Z drugiej strony widzę, że wielu programistów JavaScript ma tendencję do sięgania po swoją ulubioną wtyczkę JS, aby ułatwić sobie pracę, nawet jeśli zadanie to może nie wymagać wszystkich dzwonków i gwizdów, które zapewnia dana wtyczka.
Zastrzeżenie: Korzystanie z jednej z wielu dostępnych wtyczek ma oczywiście swoje zalety. Otrzymasz wiele opcji, których możesz użyć do dostosowania do swoich potrzeb bez konieczności kodowania. Ponadto większość autorów wtyczek optymalizuje swój kod, czyni go kompatybilnym z różnymi przeglądarkami i platformami i tak dalej. Ale nadal otrzymujesz pełnowymiarową bibliotekę dołączoną do twojego projektu, być może tylko dla jednej lub dwóch różnych rzeczy, które zapewnia. Nie mówię, że używanie jakiejkolwiek wtyczki innej firmy jest naturalnie złą rzeczą, robię to na co dzień w moich projektach, tylko ogólnie dobrym pomysłem jest rozważenie zalet i wad każdego podejścia, tak jak jest dobra praktyka w kodowaniu. Jeśli chodzi o robienie własnych rzeczy w ten sposób, wymaga to nieco większej wiedzy i doświadczenia w zakresie kodowania, aby wiedzieć, czego szukasz, ale w końcu powinieneś otrzymać kawałek kodu, który robi jedną rzecz i jedną tylko w sposób chcesz.
Ten artykuł ma na celu pokazanie czystego podejścia CSS/JS w tworzeniu pełnoekranowego układu suwaka wyzwalanego przewijaniem z niestandardową animacją treści. W tym pomniejszonym podejściu omówię podstawową strukturę HTML, której można oczekiwać od zaplecza CMS, nowoczesne techniki układu CSS (SCSS) i waniliowe kodowanie JavaScript dla pełnej interaktywności. Będąc podstawowymi, koncepcja ta może być łatwo rozszerzona na wtyczkę na większą skalę i / lub używana w różnych aplikacjach, które nie mają żadnych zależności w swoim rdzeniu.
Projekt, który zamierzamy stworzyć, to minimalistyczna wizytówka portfolio architekta z wyróżnionymi zdjęciami i tytułami każdego projektu. Cały slider z animacjami będzie wyglądał tak:
Możesz sprawdzić demo tutaj i uzyskać dostęp do mojego repozytorium Github, aby uzyskać więcej informacji.
Przegląd HTML
Oto podstawowy kod HTML, z którym będziemy pracować:
<div> <div class="mask"> <!-- Textual logo will go here --> </div> <div> <div class="slides"> <!-- Featured image slides will go here --> </div> <div class="slides mask"> <!-- Slide titles will go here --> </div> </div> <div> <!-- Static info on the right --> </div> <nav> <!-- Current slide indicator --> </nav> </div>
Naszym głównym posiadaczem jest div z identyfikatorem hero-slider
. Wewnątrz układ podzielony jest na sekcje:
- Logo (sekcja statyczna)
- Pokaz slajdów, nad którym będziemy głównie pracować
- Informacje (sekcja statyczna)
- Nawigacja suwaka, która wskaże aktualnie aktywny slajd, a także całkowitą liczbę slajdów
Skupmy się na sekcji pokazu slajdów, ponieważ jest to nasz punkt zainteresowania w tym artykule. Tutaj mamy dwie części — główną i aux . Main to div, który zawiera polecane obrazy, podczas gdy aux zawiera tytuły obrazów. Struktura każdego slajdu wewnątrz tych dwóch uchwytów jest dość podstawowa. Tutaj mamy slajd obrazu wewnątrz głównego uchwytu:
<div class="slide" data-index="0"> <div class="abs-mask"> <div class="slide-image"> </div> </div> </div>
Atrybut danych indeksu służy do śledzenia tego, w którym miejscu pokazu slajdów się znajdujemy. Element div maski abs, którego użyjemy do stworzenia ciekawego efektu przejścia, a element div obrazu slajdu zawiera konkretny wyróżniony obraz. Obrazy są renderowane inline tak, jakby pochodziły bezpośrednio z CMS i są ustawiane przez użytkownika końcowego.
Podobnie tytuł wsuwa się do uchwytu pomocniczego:
<h2 class="slide-title slide" data-index="0"><a href="#">#64 Paradigm</a></h2>
Każdy tytuł slajdu to znacznik H2 z odpowiednim atrybutem danych i łączem prowadzącym do pojedynczej strony tego projektu.
Reszta naszego kodu HTML również jest dość prosta. Mamy logo u góry, statyczne informacje, które mówią użytkownikowi, na której stronie się znajduje, opis i wskaźnik bieżącego/całkowitego suwaka.
Przegląd CSS
Kod źródłowy CSS jest napisany w SCSS, preprocesorze CSS, który jest następnie kompilowany do zwykłego CSS, który przeglądarka może interpretować. SCSS daje przewagę w postaci używania zmiennych, selekcji zagnieżdżonej, domieszek i innych fajnych rzeczy, ale musi być skompilowany do CSS, aby przeglądarka odczytała kod tak, jak powinna. Na potrzeby tego samouczka użyłem Scout-App do obsługi kompilacji, ponieważ chciałem mieć narzędzia w absolutnym minimum.
Użyłem flexboxa do obsługi podstawowego układu side-by-side. Pomysł polega na tym, aby pokaz slajdów był po jednej stronie, a sekcja informacyjna po drugiej.
#hero-slider { position: relative; height: 100vh; display: flex; background: $dark-color; } #slideshow { position: relative; flex: 1 1 $main-width; display: flex; align-items: flex-end; padding: $offset; } #info { position: relative; flex: 1 1 $side-width; padding: $offset; background-color: #fff; }
Zanurzmy się w pozycjonowanie i ponownie skupmy się na sekcji pokazu slajdów:
#slideshow { position: relative; flex: 1 1 $main-width; display: flex; align-items: flex-end; padding: $offset; } #slides-main { @extend %abs; &:after { content: ''; @extend %abs; background-color: rgba(0, 0, 0, .25); z-index: 100; } .slide-image { @extend %abs; background-position: center; background-size: cover; z-index: -1; } } #slides-aux { position: relative; top: 1.25rem; width: 100%; .slide-title { position: absolute; z-index: 300; font-size: 4vw; font-weight: 700; line-height: 1.3; @include outlined(#fff); } }
Ustawiłem główny suwak, aby był pozycjonowany bezwzględnie, a obrazy tła rozciągały cały obszar za pomocą właściwości background-size: cover
. Aby zapewnić większy kontrast z tytułami slajdów, ustawiłem absolutny pseudoelement, który działa jak nakładka. Suwak pomocniczy zawierający tytuły slajdów jest umieszczony na dole ekranu i na górze obrazów.
Ponieważ tylko jeden slajd będzie widoczny na raz, ustawiłem również każdy tytuł jako bezwzględny i kazałem obliczyć rozmiar posiadacza za pomocą JS, aby upewnić się, że nie ma żadnych odcięć, ale więcej na ten temat w jednej z naszych nadchodzących sekcji. Tutaj możesz zobaczyć użycie funkcji SCSS zwanej rozszerzaniem:
%abs { position: absolute; top: 0; left: 0; height: 100%; width: 100%; }
Ponieważ dużo używałem pozycjonowania bezwzględnego, przeciągnąłem ten CSS do rozszerzenia, aby był łatwo dostępny w różnych selektorach. Stworzyłem również mixin o nazwie „zarysowany”, aby zapewnić podejście DRY podczas stylizacji tytułów i tytułu głównego suwaka.
@mixin outlined($color: $dark-color, $size: 1px) { color: transparent; -webkit-text-stroke: $size $color; }
Jeśli chodzi o część statyczną tego układu, nie ma w tym nic skomplikowanego, ale tutaj można zobaczyć ciekawą metodę pozycjonowania tekstu, który musi znajdować się na osi Y zamiast normalnego przepływu:
.slider-title-wrapper { position: absolute; top: $offset; left: calc(100% - #{$offset}); transform-origin: 0% 0%; transform: rotate(90deg); @include outlined; }
Chciałbym zwrócić twoją uwagę na właściwość transform-origin
, ponieważ stwierdziłem, że jest ona naprawdę niedostatecznie wykorzystywana w tego typu układzie. Sposób, w jaki ten element jest pozycjonowany, polega na tym, że jego kotwica pozostaje w lewym górnym rogu elementu, ustawiając punkt obrotu i zapewniając ciągły przepływ tekstu od tego punktu w dół, bez problemów z różnymi rozmiarami ekranu.
Rzućmy okiem na ciekawszą część CSS - wstępną animację ładowania:
Zwykle tego rodzaju zsynchronizowane zachowanie animacji uzyskuje się za pomocą biblioteki — na przykład GSAP jest jedną z najlepszych na rynku, zapewniając doskonałe możliwości renderowania, jest łatwy w użyciu i ma funkcję osi czasu, która umożliwia programiście programowe łączenie elementów przejścia w siebie.
Jednakże, ponieważ jest to czysty przykład CSS/JS, zdecydowałem się na naprawdę podstawowe podejście. Tak więc każdy element jest domyślnie ustawiony na swoją pozycję początkową - albo ukryty przez transformację lub przezroczystość i wyświetlany po załadowaniu suwaka, który jest wyzwalany przez nasz JS. Wszystkie właściwości przejścia są ręcznie dostosowywane, aby zapewnić naturalny i interesujący przepływ, a każde przejście przechodzi w inne, zapewniając przyjemne wrażenia wizualne.
#logo:after { transform: scaleY(0); transform-origin: 50% 0; transition: transform .35s $easing; } .logo-text { display: block; transform: translate3d(120%, 0, 0); opacity: 0; transition: transform .8s .2s, opacity .5s .2s; } .current, .sep:before { opacity: 0; transition: opacity .4s 1.3s; } #info { transform: translate3d(100%, 0, 0); transition: transform 1s $easing .6s; } .line { transform-origin: 0% 0; transform: scaleX(0); transition: transform .7s $easing 1s; } .slider-title { overflow: hidden; >span { display: block; transform: translate3d(0, -100%, 0); transition: transform .5s 1.5s; } }
Jeśli jest coś, co chciałbym, abyś tutaj zobaczył, to użycie właściwości transform
. Podczas przenoszenia elementu HTML, niezależnie od tego, czy jest to przejście, czy animacja, zaleca się użycie właściwości transform
. Widzę wielu ludzi, którzy mają tendencję do używania marginesów lub dopełnienia, a nawet przesunięć — góra, lewo itd., co nie daje odpowiednich wyników, jeśli chodzi o renderowanie.
Aby uzyskać głębsze zrozumienie tego, jak używać CSS podczas dodawania zachowań interaktywnych, nie mogę wystarczająco polecić poniższego artykułu.
Jest autorstwa Paula Lewisa, inżyniera Chrome i obejmuje prawie wszystko, co należy wiedzieć o renderowaniu pikseli w Internecie, niezależnie od tego, czy jest to CSS, czy JS.
Przegląd JavaScript i logika suwaka
Plik JavaScript jest podzielony na dwie odrębne funkcje.
Funkcja heroSlider
, która zajmuje się całą potrzebną nam tutaj funkcjonalnością, oraz funkcja utils
, w której dodałem kilka funkcji użytkowych wielokrotnego użytku. Skomentowałem każdą z tych funkcji użytkowych, aby zapewnić kontekst, jeśli chcesz ponownie wykorzystać je w swoim projekcie.
Główna funkcja jest zakodowana w taki sposób, że ma dwie gałęzie: init
i resize
. Te gałęzie są dostępne po powrocie funkcji głównej i są wywoływane w razie potrzeby. init
jest inicjalizacją funkcji głównej i jest wyzwalana w przypadku załadowania okna. Podobnie gałąź zmiany rozmiaru jest wyzwalana przy zmianie rozmiaru okna. Jedynym celem funkcji zmiany rozmiaru jest ponowne obliczenie rozmiaru suwaka tytułu przy zmianie rozmiaru okna, ponieważ rozmiar czcionki tytułu może się różnić.
W funkcji heroSlider
udostępniłem obiekt suwaka, który zawiera wszystkie potrzebne nam dane i selektory:
const slider = { hero: document.querySelector('#hero-slider'), main: document.querySelector('#slides-main'), aux: document.querySelector('#slides-aux'), current: document.querySelector('#slider-nav .current'), handle: null, idle: true, activeIndex: -1, interval: 3500 };
Na marginesie, to podejście można łatwo dostosować, jeśli na przykład używasz Reacta, ponieważ możesz przechowywać dane w stanie lub użyć nowo dodanych hooków. Aby pozostać na miejscu, przyjrzyjmy się, co reprezentuje każda z par klucz-wartość tutaj:

- Pierwsze cztery właściwości to odwołanie HTML do elementu DOM, którym będziemy manipulować.
- Właściwość
handle
będzie używana do uruchamiania i zatrzymywania funkcji autoodtwarzania. - Właściwość
idle
to flaga, która uniemożliwia użytkownikowi wymuszenie przewijania podczas przejścia slajdu. -
activeIndex
pozwoli nam śledzić aktualnie aktywny slajd -
interval
oznacza interwał autoodtwarzania suwaka
Podczas inicjalizacji suwaka wywołujemy dwie funkcje:
setHeight(slider.aux, slider.aux.querySelectorAll('.slide-title')); loadingAnimation();
Funkcja setHeight
sięga do funkcji użytkowej, aby ustawić wysokość naszego suwaka pomocniczego w oparciu o maksymalny rozmiar tytułu. W ten sposób zapewniamy odpowiedni rozmiar i żaden tytuł slajdu nie zostanie ucięty, nawet jeśli jego zawartość spadnie do dwóch wierszy.
Funkcja loadAnimation dodaje klasę CSS do elementu dostarczającego intro przejścia CSS:
const loadingAnimation = function () { slider.hero.classList.add('ready'); slider.current.addEventListener('transitionend', start, { once: true }); }
Ponieważ nasz wskaźnik suwaka jest ostatnim elementem na osi czasu przejścia CSS, czekamy na jego zakończenie i wywołujemy funkcję start. Podając dodatkowy parametr jako obiekt, zapewniamy, że zostanie to wywołane tylko raz.
Przyjrzyjmy się funkcji startu:
const start = function () { autoplay(true); wheelControl(); window.innerWidth <= 1024 && touchControl(); slider.aux.addEventListener('transitionend', loaded, { once: true }); }
Kiedy więc układ się skończy, jego początkowe przejście jest wyzwalane przez funkcję loadingAnimation
i przejmuje ją funkcja start. Następnie uruchamia funkcję autoodtwarzania, włącza sterowanie kółkiem, określa, czy jesteśmy na urządzeniu dotykowym, czy stacjonarnym, i czeka na pierwsze przejście slajdu tytułów, aby dodać odpowiednią klasę CSS.
Automatyczne odtwarzanie
Jedną z podstawowych funkcji tego układu jest funkcja autoodtwarzania. Przyjrzyjmy się odpowiedniej funkcji:
const autoplay = function (initial) { slider.autoplay = true; slider.items = slider.hero.querySelectorAll('[data-index]'); slider.total = slider.items.length / 2; const loop = () => changeSlide('next'); initial && requestAnimationFrame(loop); slider.handle = utils().requestInterval(loop, slider.interval); }
Najpierw ustawiamy flagę autoodtwarzania na true, wskazując, że suwak jest w trybie autoodtwarzania. Ta flaga jest przydatna podczas określania, czy ponownie uruchomić autoodtwarzanie po interakcji użytkownika z suwakiem. Następnie odwołujemy się do wszystkich elementów suwaka (slajdów), ponieważ zmienimy ich aktywną klasę i obliczymy całkowitą liczbę iteracji suwaka, dodając wszystkie elementy i dzieląc przez dwa, ponieważ mamy dwa zsynchronizowane układy suwaków (główny i pomocniczy) ale tylko jeden „suwak” per se, który zmienia oba jednocześnie.
Najbardziej interesującą częścią kodu jest tutaj funkcja pętli. Wywołuje slideChange
, podając kierunek slajdu, który omówimy za minutę, jednak funkcja pętli jest wywoływana kilka razy. Zobaczmy dlaczego.
Jeśli początkowy argument zostanie oceniony jako prawdziwy, wywołamy funkcję pętli jako wywołanie zwrotne requestAnimationFrame
. Dzieje się tak tylko przy pierwszym obciążeniu suwaka, które powoduje natychmiastową zmianę suwaka. Używając requestAnimationFrame
wykonujemy podane wywołanie zwrotne tuż przed kolejnym odświeżeniem ramki.
Jednak, ponieważ chcemy kontynuować slajdy w trybie autoodtwarzania, użyjemy powtórnego wywołania tej samej funkcji. Zwykle osiąga się to za pomocą setInterval. Ale w tym przypadku użyjemy jednej z funkcji narzędziowych requestInterval
. Podczas gdy setInterval
działa dobrze, requestInterval
to zaawansowana koncepcja, która opiera się na requestAnimationFrame
i zapewnia bardziej wydajne podejście. Zapewnia, że funkcja zostanie ponownie uruchomiona tylko wtedy, gdy aktywna jest karta przeglądarki.
Więcej o tej koncepcji w tym niesamowitym artykule można znaleźć na temat sztuczek CSS. Zauważ, że przypisujemy wartość zwracaną z tej funkcji do naszej właściwości slider.handle
. Ten unikalny identyfikator, który zwraca funkcja, jest dla nas dostępny i użyjemy go, aby później anulować autoodtwarzanie za pomocą cancelAnimationFrame
.
Zmiana slajdu
Główną funkcją całej koncepcji jest funkcja slideChange
. Zmienia slajdy, niezależnie od tego, czy jest to autoodtwarzanie, czy wyzwalacz użytkownika. Jest świadomy kierunku suwaka, zapewnia pętlę, więc gdy dojdziesz do ostatniego slajdu, będziesz mógł przejść do pierwszego slajdu. Oto jak to zakodowałem:
const changeSlide = function (direction) { slider.idle = false; slider.hero.classList.remove('prev', 'next'); if (direction == 'next') { slider.activeIndex = (slider.activeIndex + 1) % slider.total; slider.hero.classList.add('next'); } else { slider.activeIndex = (slider.activeIndex - 1 + slider.total) % slider.total; slider.hero.classList.add('prev'); } //reset classes utils().removeClasses(slider.items, ['prev', 'active']); //set prev const prevItems = [...slider.items] .filter(item => { let prevIndex; if (slider.hero.classList.contains('prev')) { prevIndex = slider.activeIndex == slider.total - 1 ? 0 : slider.activeIndex + 1; } else { prevIndex = slider.activeIndex == 0 ? slider.total - 1 : slider.activeIndex - 1; } return item.dataset.index == prevIndex; }); //set active const activeItems = [...slider.items] .filter(item => { return item.dataset.index == slider.activeIndex; }); utils().addClasses(prevItems, ['prev']); utils().addClasses(activeItems, ['active']); setCurrent(); const activeImageItem = slider.main.querySelector('.active'); activeImageItem.addEventListener('transitionend', waitForIdle, { once: true }); }
Pomysł polega na określeniu aktywnego slajdu na podstawie jego indeksu danych, który otrzymaliśmy z HTML. Zajmijmy się każdym krokiem:
- Ustaw flagę bezczynności suwaka na wartość false. Oznacza to, że trwa zmiana slajdu, a gesty za pomocą kółka i dotyku są wyłączone.
- Poprzednia klasa CSS suwaka kierunku zostaje zresetowana i sprawdzamy, czy jest nowa. Parametr kierunku podawany jest domyślnie jako „next”, jeśli pochodzimy z funkcji autoodtwarzania, lub przez funkcję wywołaną przez użytkownika –
wheelControl
lubtouchControl
. - Na podstawie kierunku obliczamy indeks aktywnego slajdu i dostarczamy do suwaka aktualną klasę CSS kierunku. Ta klasa CSS służy do określenia, jaki efekt przejścia zostanie użyty (np. od prawej do lewej lub od lewej do prawej)
- Slajdy otrzymują swoje „stanowe” klasy CSS (poprzednie, aktywne) za pomocą innej funkcji narzędziowej, która usuwa klasy CSS, ale może być wywoływana na NodeList, a nie tylko na pojedynczym elemencie DOM. Następnie tylko poprzednie i aktualnie aktywne slajdy są dodawane do tych klas CSS. Dzięki temu CSS może kierować tylko te slajdy i zapewnia odpowiednie przejścia.
-
setCurrent
to wywołanie zwrotne, które aktualizuje wskaźnik suwaka na podstawie activeIndex. - Na koniec czekamy na zakończenie przejścia aktywnego slajdu obrazu, aby wyzwolić wywołanie zwrotne
waitForIdle
, które ponownie uruchomi autoodtwarzanie, jeśli zostało wcześniej przerwane przez użytkownika.
Kontrola użytkownika
W oparciu o rozmiar ekranu dodałem dwa rodzaje kontrolek użytkownika – kółko i dotyk. Sterowanie kołami:
const wheelControl = function () { slider.hero.addEventListener('wheel', e => { if (slider.idle) { const direction = e.deltaY > 0 ? 'next' : 'prev'; stopAutoplay(); changeSlide(direction); } }); }
Tutaj słuchamy nawet koła i jeśli suwak jest aktualnie w trybie bezczynności (nie animuje aktualnie zmiany slajdu), określamy kierunek koła, wywołujemy stopAutoplay
, aby zatrzymać funkcję autoodtwarzania, jeśli jest w toku, i zmieniamy slajd w zależności od kierunku. Funkcja stopAutoplay
to nic innego jak prosta funkcja, która ustawia naszą flagę autoodtwarzania na wartość false i anuluje nasz interwał, wywołując funkcję użytkową cancelRequestInterval
przekazując jej odpowiedni uchwyt:
const stopAutoplay = function () { slider.autoplay = false; utils().clearRequestInterval(slider.handle); }
Podobnie jak w przypadku wheelControl
, mamy touchControl
, który zajmuje się gestami dotykowymi:
const touchControl = function () { const touchStart = function (e) { slider.ts = parseInt(e.changedTouches[0].clientX); window.scrollTop = 0; } const touchMove = function (e) { slider.tm = parseInt(e.changedTouches[0].clientX); const delta = slider.tm - slider.ts; window.scrollTop = 0; if (slider.idle) { const direction = delta < 0 ? 'next' : 'prev'; stopAutoplay(); changeSlide(direction); } } slider.hero.addEventListener('touchstart', touchStart); slider.hero.addEventListener('touchmove', touchMove); }
Nasłuchujemy dwóch wydarzeń: touchstart
i touchmove
. Następnie obliczamy różnicę. Jeśli zwraca wartość ujemną, przechodzimy do następnego slajdu, gdy użytkownik przesuwał palcem od prawej do lewej. Z drugiej strony, jeśli wartość jest dodatnia, co oznacza, że użytkownik przesunął się od lewej do prawej, uruchamiamy slideChange
z kierunkiem przekazanym jako „poprzedni”. W obu przypadkach funkcja autoodtwarzania zostaje zatrzymana.
Jest to dość prosta implementacja gestów użytkownika. Aby to wykorzystać, możemy dodać przyciski poprzedni/następny, aby wywołać slideChange
po kliknięciu lub dodać listę punktowaną, aby przejść bezpośrednio do slajdu na podstawie jego indeksu.
Podsumowanie i końcowe przemyślenia na temat CSS
Więc proszę bardzo, czysty sposób CSS/JS kodowania niestandardowego układu suwaka z nowoczesnymi efektami przejścia.
Mam nadzieję, że uznasz to podejście za przydatne jako sposób myślenia i możesz użyć czegoś podobnego w swoich projektach front-endowych podczas kodowania projektu, który niekoniecznie był konwencjonalnie zaprojektowany.
Dla tych, którzy są zainteresowani efektem przejścia obrazu, omówię to w kilku następnych wierszach.
Jeśli ponownie przyjrzymy się strukturze HTML slajdów, którą podałem we wstępie, zobaczymy, że każdy slajd ma wokół siebie znacznik div
z klasą CSS abs-mask
. To, co robi ten div
, polega na tym, że ukrywa część widocznego obrazu o określoną wartość, używając funkcji overflow:hidden
i przesuwając ją w innym kierunku niż obraz. Na przykład, jeśli spojrzymy na kodowanie poprzedniego slajdu:
&.prev { z-index: 5; transform: translate3d(-100%, 0, 0); transition: 1s $easing; .abs-mask { transform: translateX(80%); transition: 1s $easing; } }
Poprzedni slajd ma przesunięcie -100% na swojej osi X, przesuwając go na lewo od bieżącego slajdu, jednak wewnętrzny element div abs-mask
jest przesunięty o 80% w prawo, co zapewnia węższy widok. To, w połączeniu z większym indeksem Z dla aktywnego slajdu, daje efekt okładki — aktywny obraz zakrywa poprzedni, jednocześnie rozszerzając swój widoczny obszar poprzez przesuwanie maski, która zapewnia pełny widok.