Анімація
зміна вигляду сторінки, розгорнута в часі
Що це таке
Анімація у вебі найчастіше означає CSS-анімацію: іменовану послідовність
ключових кадрів (keyframes), записану один раз у правилі @keyframes і
прив’язану до елемента через властивості animation. Специфікація W3C CSS
Animations Level 1 описує цей механізм як спосіб «to animate the values of CSS
properties over time, using keyframes», тобто анімувати значення властивостей у
часі за допомогою ключових кадрів. Рухаються також анімовані зображення, відео
й малювання на canvas; ця стаття стосується декларативного різновиду.
Кожен ключовий кадр задає значення властивостей у певній точці циклу: from або
0% на початку, to або 100% наприкінці й будь-які відсотки між ними.
Проміжні значення браузер обчислює сам. Інші властивості анімації визначають,
скільки триває один цикл, скільки разів він повторюється, чи грає кожен другий
цикл у зворотному напрямку і чи анімація виконується, чи стоїть на паузі.
Значення infinite для кількості повторів, за словами специфікації, означає, що
анімація «will repeat forever», тобто повторюватиметься безкінечно.
animation-fill-mode визначає, що показує елемент поза циклом: за none
анімація тоді не діє, backwards застосовує перший ключовий кадр протягом паузи
перед стартом, якщо вона є, а forwards зберігає значення, на яких анімація
завершилася.
Перехід (transition) — найближчий родич: там, де змінене значення властивості зазвичай з’явилося б одразу, CSS Transitions розтягує зміну на задану тривалість. CSS Animations проводить межу між ними так: переходи запускаються неявно, коли змінюється значення властивості, а анімації виконуються явно, коли застосовано властивості анімації. Посилання, колір якого плавно змінюється під курсором, — це перехід; індикатор завантаження, що обертається незалежно від того, чи щось змінилося, — анімація.
Новіша специфікація, Scroll-driven Animations, замінює годинник самою сторінкою. Анімація, прив’язана до часової шкали прогресу прокручування, просувається в міру того, як прокручується контейнер прокручування: від 0% на початку діапазону прокручування до 100% наприкінці. Коли ці дві позиції збігаються, бо прокручувати нічого, специфікація називає шкалу неактивною.
Чому це важливо
Рух притягує увагу, і це водночас і причина ним користуватися, і головна проблема з ним.
Декому з читачів він фізично неприємний. Документ Understanding до критерію успіху 2.3.3 у WCAG 2.2 пояснює, що елементи, які рухаються під час прокручування сторінки, можуть викликати реакції в людей із вестибулярними розладами, тобто розладами внутрішнього вуха: запаморочення, нудоту й головний біль. Документ називає паралакс-прокручування, за якого тло рухається з іншою швидкістю, ніж передній план, анімацією, яка часто не є суттєвою, і зазначає, що наслідки бувають настільки серйозними, що для відновлення потрібен постільний режим.
Читач може про це сказати, а сторінка — запитати. Media Queries Level 5
визначає prefers-reduced-motion, медіафункцію з двома значеннями. reduce
означає, що читач повідомив системі про перевагу інтерфейсу, який «removes or
replaces the types of motion-based animation», тобто прибирає або замінює ті
види анімації з рухом, що викликають дискомфорт у людей із вестибулярною
чутливістю до руху чи відволікають людей із порушеннями уваги. no-preference
означає, що вподобання невідоме, і коли функцію перевіряють саму по собі, це
значення обчислюється як хибне.
Цьому присвячено два критерії успіху. 2.2.2 Pause, Stop, Hide, рівня A, стосується вмісту, що рухається, блимає чи прокручується, запускається автоматично, триває понад п’ять секунд і показується поряд з іншим вмістом: читач повинен мати змогу призупинити, зупинити чи приховати його, якщо рух не є суттєвим. Критерій стосується всього на сторінці, а анімація, яка зупиняється лише тоді, коли на ній фокус, паузою не вважається. 2.3.3 Animation from Interactions, рівня AAA, вимагає, щоб анімацію руху, запущену взаємодією, можна було вимкнути, якщо вона не суттєва. Документ Understanding до нього називає функцію зменшення руху в браузері чи операційній системі одним зі способів його виконати.
Не кожна зміна — це рух. WCAG визначає анімацію руху як кроки, додані між станами, щоб створити ілюзію руху чи відчуття плавного переходу. Елемент, який, з’являючись, пересувається на місце або змінює розмір, анімований; елемент, що з’являється миттєво, — ні. Зміна кольору чи непрозорості, яка не змінює сприйманого розміру, форми й положення елемента, під визначення не підпадає, і тому зменшення руху не означає, що треба заморозити кожне плавне згасання.
Як це виглядає на практиці
Найнаочніший урок починається з правила, яке здавалося завершеним. Сайт враховував налаштування зменшення руху одним універсальним правилом, що вимикало всі переходи; воно мало вигляд вичерпного й проходило лінтер, але за емульованого налаштування одинадцять селекторів і далі анімувалися. Під час роботи, після якої режим зменшеного руху справді запрацював, причину знайдено в специфічності: універсальний селектор програє будь-якому правилу з класом, а саме такими є всі продумані анімації на сторінці. Усе, що рухається, тепер зібрано в одній частині таблиці стилів, яка підключається наприкінці, а лінтер відхиляє перехід властивості transform будь-де поза нею. Межа проходить між рухом і кольором: перехід кольору перевірку проходить, а перехід руху — ні. Рух також задають переходом, а не анімацією з ключовими кадрами, бо перехід скасувати елементарно, а анімацію — ні. Як сказано на сторінці, правило, що програє за специфічністю, дає збій непомітно.
Анімація, прив’язана до прокручування, має й власну ваду. Серед 11 дефектів доступності, які браузер вважав справними, була саме така анімація, яка на надто короткій для прокручування сторінці лишається неактивною і назавжди обрізала футер на трьох сторінках. Автоматичні перевірки її пропустили, бо дефект стосувався того, як сторінка відображається, а не розмітки.
Лінтер здатен зробити перевірку обов’язковою. Дизайн-система з 48 токенів, побудована на власному скляному матеріалі платформи, має рух як одну з шести груп токенів, а її лінтер відхиляє анімацію, оголошену без урахування налаштування зменшення руху. Сторінка пояснює чому: анімацію додають під час фінального шліфування, і пропускають якраз перевірку налаштування, тож правило не дає навіть написати анімацію без такої перевірки.
Таблиці стилів цього сайту показують ті самі звички і в інших місцях. Дві
шестерні в шапці сайту обертаються циклами по 60 і 96 секунд, а за значення
reduce обидві отримують animation: none. Їхній паралакс, прив’язаний до
прокручування, захищено двічі: всередині prefers-reduced-motion: no-preference
і всередині перевірки @supports для animation-timeline: scroll(); у
браузері без цієї можливості шестерні лишаються на місці, і коментар називає
саме такий запасний варіант дизайном. У футері нижній блок, до якого входить і
позначка авторського права, отримує прихований стан від зворотного заповнення
анімації (backwards fill), а не від оголошеної opacity: 0. Коментар пояснює
причину: неактивна шкала не застосовує жодного ефекту, і стара opacity: 0
ховала позначку авторського права на кожній короткій сторінці.
Де виникають проблеми
- Вимикач програє каскад. Загальне
transition: noneна універсальному селекторі майже не має специфічності, тож кожне правило з класом і далі рухається, і про це ніщо не повідомляє. Блок, розміщений після правил, які він має перебити, з переліком рухомих селекторів дає перемогу нерухомому стану. - Налаштування додають пізніше або ніколи. Анімація в базовому стилі
рухається для всіх, доки хтось не згадає її вимкнути. Якщо оголосити її
всередині
@media (prefers-reduced-motion: no-preference), типовим станом стає нерухомість. - Шкала прокручування потрапляє на сторінку без прокручування. Шкала
неактивна, і анімація нічого не робить, тож початковий стан, записаний у
базовому стилі, наприклад
opacity: 0, яку мала прибрати анімація, лишається чинним. Початковий стан, заданий зворотним заповненням, зникає разом з анімацією. - Значення ключового кадру, яке браузер відкидає, випадає тихо. Специфікація каже, що коли властивість у ключовому кадрі задано з недійсним значенням, її анімація відбувається так, ніби цього кадру не існує. Значення з друкарською помилкою пропускає крок без жодного повідомлення про помилку.
- Декоративний цикл неможливо зупинити. Анімація
infinite, що запускається під час завантаження поряд із текстом, підпадає під 2.2.2, щойно триває довше за п’ять секунд; виконати критерій допомагає елемент керування для паузи або завершення протягом п’яти секунд. - «Зменшити» читають як «прибрати все». Якщо вирізати кожну зміну стану, разом із рухом може зникнути й інформація. Новий стан, показаний миттєво або через плавну появу, зберігає інформацію без руху.
Що почитати далі
- CSS Animations Level 1
— правило
@keyframes, властивості анімації, режими заповнення й події, які надсилає анімація. - CSS Transitions Level 1 — як зміну значення властивості розтягують на певну тривалість замість миттєвого застосування.
- Scroll-driven Animations
— часові шкали прогресу прокручування, нотація
scroll()і випадки, коли шкала неактивна. - Media Queries Level 5: prefers-reduced-motion
— два значення і те, про що просить читач, який вибирає
reduce. - Understanding SC 2.2.2: Pause, Stop, Hide — межа в п’ять секунд, що вважається автоматичним запуском і які механізми паузи прийнятні.
- Understanding SC 2.3.3: Animation from Interactions — вестибулярні реакції, паралакс і налаштування зменшення руху як один зі способів виконати критерій.