Створюємо ефект плавного появи слів за допомогою Web Animation API

31

Від автора: нещодавно мені показали кілька прикладів ефекту плавного появи слів. Схожий візуальний ефект можна побачити в фентезі та пригодницьких фільмах. Всі способи, які я бачив, вимагають багато розмітки і великих фреймворків, але тут я зрозумів, що ефект можна з легкістю відтворити з допомогою JavaScript Web Animation API.

На старт

Демонстрація кінцевого ефекту. Почнемо ми з розмітки: якщо JS не спрацює з яких-небудь причин, користувач хоча б зможе прочитати текст (будемо створювати ефект за методикою прогресивного поліпшення). Для цього я візьму теги blockquote, q cite:

What we think, we become.
Gautama Buddha

Увагу

Базові налаштування шрифту вказуємо в CSS:

blockquote {
font-size: 3rem;
}
cite {
display: block;
text-align: right;
font-family: Verdana, Arial, sans-serif;
margin-top: 1rem;
font-size: .9rem;
color: #aaa;
font-style: normal;
}
blockquote q {
font-family: Georgia, serif;
font-style: italic;
letter-spacing: .1rem;
}

Чим гарний тег — відкривають і закривають лапки можна кастомизировать через CSS. Отрисовывая їх у вигляді псевдоелемент, ми забираємо їх з HTML:

q {
quotes: «»» «»» «‘» «‘»;
}
q:before {
content: open-quote;
margin-right: .8rem;
}
q:after {
content: close-quote;
}
q:before, q:after {
color: #ccc;
font-size: 4rem;
}

JS код, який ми зараз додамо, буде обертати всі слова в тег span. CSS нижче буде застосовуватися до цих елементів тільки в тому випадку, якщо працює JS. Якщо JS не працює, до HTML застосовуватися тільки перші стилі.

blockquote q span {
will-change: opacity, filter;
opacity: 0;
filter: blur(0px);
}

Властивість will-change – попередження рендеринг движку браузера, що певні властивості (opacity і blur) будуть анімовані. Дана властивість готує браузер і оптимізує анімацію.

Марш

Скрипт, який ми додаємо в кінець сторінки, ділиться на три функції: генератор випадкових чисел, функцію, яка розбиває контент цитати на окремі слова і оточує їх в тег span, а також сама анімація. Почну з другої функції:

function splitWords() {
let quote = document.querySelector(«blockquote q»),
quotewords = quote.innerText.split(» «),
wordCount = quotewords.length;
quote.innerHTML = «»;
for (let i=0; i < wordCount; i++) {
quote.innerHTML += ««+quotewords+»«;
if (i < quotewords.length — 1) {
quote.innerHTML += » «;
}
}
quotewords = document.querySelectorAll(«blockquote q span»);
fadeWords(quotewords);
}

З незвичайного тут є перевірка змінної i на кількість слів у цитаті. Кожне слово в цитаті отримує додатковий пробіл праворуч крім останнього.

Масив слів передається у функцію fadeWords, яка використовує наступну функцію:

function getRandom(min, max) {
return Math.random() * (max — min) + min;
}

Сама функція fadeWords:

function fadeWords(quotewords) {
Array.prototype.forEach.call(quotewords, function(word) {
let animate = word.animate([{
opacity: 0,
filter: «blur(«+getRandom(2,5)+»px)»
}, {
opacity: 1,
filter: «blur(0px)»
}],
{
duration: 1000,
delay: getRandom(500,3300),
fill: «forwards»
}
)
})
}

Всі теги span змінюють значення opacity з 0 до 1, розмиття поступово зменшується. Анімація триває одну секунду, але у кожного елемента випадкова затримка, тобто слова почнуть плавно з’являтися у різний час (або, принаймні, повинні).

Все починається з виклику функції splitWords в кінці скрипта:

splitWords();

Можна поліпшити цей метод можна послідовно плавно показувати слова (збільшуючи за инкременту затримку кожного слова). Також можна вибірково показувати слова (для цього необхідно додавати теги span з різними класами певними словами, а скрипт повинен вибирати випадково ці слова). Решту віддам на відкуп вашій уяві…