Показване при скрол (част 3 – AOS)
И след като се запознахме с основите на подобни ефекти, нека приложим анимациите с AOS.
Анимации с AOS
AOS е съкращение от „Animate on Scroll“ (анимации при скрол). В общи линии върши това, което написахме custom предния път. Защо тогава да зареждаме допълнително 20KB JS, като имаме едни 20-30 реда, които вършат същата работа? Защото AOS всъщност върши повече.
AOS е библиотека, върху чиято разработка някой се е трудил доста повече от нас. Освен това е тествана от хиляди. За последния месец е бил изтеглен почти 80 000 пъти и то само през npm
(вероятно и има хора, които са го изтеглили директно от GitHub).
Освен, че покрива нашата функционалност, е разработена така, че конфигурацията да се прави лесно с data
-атрибути направо в HTML-а, поддържа easing функции и работи в обратна посока (при скрол нагоре крие обратно елементите пак с анимация). И това са само най-основните преимущества.
Мигриране към AOS
Нека копираме файловете си от предния път, като премахнем functions.js
файла (той няма да ни е нужен), както и animate.css
стиловете. AOS идва със свои стилове, но ако по някаква причина държите да ползвате Animate.CSS, AOS го позволява с малко допълнителни настройки.
Да добавим и кода на самия AOS. Аз използвах npm
, така че имам и source файлове и dependency-та, но вие можете просто да използвате CDN-а описан най-долу на http://michalsnik.github.io/aos/.
След това нека изтрием всички pending
класове, които бяхме добавили към елементи и вместо това им добавим data-aos="fade-up"
.
Инициализиране на анимации с AOS
За да видим някакви анимации към момента трябва да инициализираме AOS.
За целта просто добавете най-долу на страницата (преди затварящия </body>
таг):
<script>
AOS.init();
</script>
Ако презаредите страницата ще видите, че вече сме почти готови. Остават обаче забавянията, които преди имахме към някои поредни елементи.
Забавяне на анимацията при поредни елементи
Изтрийте частта от CSS-а, която имахме за тях:
.feature__item.animated:nth-child(2) { animation-delay: 200ms; }
.feature__item.animated:nth-child(3) { animation-delay: 400ms; }
.media.animated { animation-delay: 200ms; }
.column__item.animated:nth-child(2) { animation-delay: 200ms; }
Към втория и третия .feature__item
можем направо в markup-а да добавим съответно data-aos-delay="150"
и data-aos-delay="300"
.
data-aos-delay="150"
добавяме и към втория .column__item
.
Когато имаме множество поредни елементи
Стигаме обаче пак до нашата галерия с 16 картинки. Както преди не искахме ръчно да добавяме delay към тях, сега това се повтаря с AOS.
В повечето случаи, ако правим нещо подобно вероятно ще използваме PHP код и тогава няма да е трудно да зададем атрибута. Просто ще имаме една променлива, която нараства със 150 всеки път и така ще е приложена на всеки таг. Тук обаче не използваме PHP и ще потърсим друг метод.
Макар и JavaScript да не е сървърен език, ние пак можем да го ползваме за генериране на markup. Можем да използваме document.write()
за „писане“ на какъвто и да е код.
Премахнете всички li.gallery__item
и на тяхно място отворете един <script>
таг.
Първо нека генерираме масив с всички номера на картинки, които ще са ни нужни (от 1 до 16).
Можем да използваме:
const indexes = Array.from(Array(16).keys());
Тъй като имаме вложени и chain-нати функции това може да е малко объркващо. Нека започнем отвътре навън:
Array(16)
създава масив с 16 празни елемента.
Когато chain-нем .keys()
към резултата, това връща итератор, където елементите са индексите на първия. Те от своя страна са числата от 0 до 15.
Ние искахме от 1 до 16, но лесно можем при принтиране на числото просто да добавяме по 1.
Това, че .keys()
не връща точно масив, а итератор за нас означава, че трябва да го преобразуваме. Това правим с Array.from()
.
Template Literals
Официално са одобрени като синтаксис на JavaScript през 2015, така че все още не всички са напълно свикнали с употребата им.
Това, което представляват е писане на string, вътре в който можем да включим директно променливи, които JS ще замени със стойностите им.
Така, че ако имаме променлива age = 18
, то
var sentence = `В България трябва да си на ${age} години, за да може да шофираш`;
ще присвои стойност на променливата sentence
, където ${age}
е заменено с 18.
Важно е вместо обикновени единични или двойни кавички ('
, "
) да се използват backticks: „`“ (клавишът се намира точно под Esc на клавиатурата).
По принцип можем да постигнем същото и просто с:
var sentence = "В България трябва да си на " + age + "години, за да може да шофираш";
Но постоянното отваряне и затваряне на кавички може да е малко изнервящо. Освен това има други специални ситуации, в които употребата на обикновени кавички и конкатениране може да доведе до изписване на още повече код.
И сега на document.write()
ще подадем следния аргумент:
indexes.map(key =>
`<li class="gallery__item" data-aos="fade-up" data-aos-delay="${(key % 4) * 150}">
<img width="420" height="420" src="gallery-${(key + 1).toString().padStart(2, '0')}.jpg" alt="cloud" />
</li>`
).join('')
Тук може да има нужда от малко повече разяснения:
indexes.map
означава, че обходим всеки елемент от масива indexes
и за обхожданата стойност ще изпълним някакъв код. Този код трябва да върне резултат, който после ще се използва в построяването на нов масив.
Така, че ако имахме const incremented = indexes.map(key => key + 1)
, тогава incremented
щеше да е нов масив със стойности от 1 до 16 (както отначало искахме), защото за всяка стойност от indexes
щеше да ѝ бъде добавено 1 и да се състави нов масив с тези стойности.
По-голямата част от самия template literal е HTML кода, който ни трябва, така че него няма да го обясняваме.
За data-aos-delay
имаме (key % 4) * 150
. Защо делим модулно на 4, вместо директно да умножаваме по 150? Защото преди трябваше всяка картинка да се покаже със закъснение спрямо предната. С AOS обаче картинките не са свързани помежду си, а при scroll на екрана се появяват едновременно 4 картинки. Така за 2ра, 3та и 4та трябва да добавим съответно по 150, 300 и 450 милисекунди закъснение.
Но при скрол още по-надолу, следващия ред не трябва да има по 600, 750 и т.н. милисекунди закъснение, тъй като до 4тия ред ще чакаме по няколко секунди докато се появят снимките.
Pad String
За пътя до самите снимки имаме (key + 1).toString().padStart(2, '0')
.
Частта + 1
е ясна – правим го, защото имаме масив от 0 до 15 (извинявам се, ако е изнервящо, че вече го повтарям 3ти път).
После се уверяваме, че числото се третира като текст чрез .toString()
. Това е нужно, защото следващата функция работи с текст, а не с числа. Тази функция padStart()
позволява към текст по-кратък от определен брой символи, в началото да повторим толкова пъти друг символ, така че да достигне търсената дължина.
Или иначе казано – при число с 1 цифра, можем да добавим 0 отпред (защото така сме си наименували картинките).
И най-накрая след всичко това имаме един .join('')
. Този .map()
, който сме направили ни връща масив с HTML кода за всяка картинка. За да го изпишем на екрана ние долепяме всеки от елементите от масива, използвайки празен string (“) за „лепило“.
Пример
И накрая имаме https://magadanski.com/demo/parallax-aos/.