Створення шаруватої анімації на SVG

15

Від автора: якщо я скажу вам, що існує формат зображення, який працює як GIF, але тільки з векторною графікою? А що якщо я скажу вам, що в цьому форматі можна змінювати напрямок анімації? А якщо так, ви можете взяти за основу одне зображення і анімувати різні його частини окремо і з різною швидкістю? Так, такий формат вже існує і це SVG. Просто потрібно проявити трохи сміливості.

Створення шаруватої анімації на SVG

У цій статті я змішаю старе з новим, взявши за основу щось примітивне і вдихнувши в це нове життя. Sass допоможе оптимізувати робочий процес і, можливо, допоможе продемонструвати автоматизацію. Іноді автоматизація може стояти на службі творчості.

Анімація, старі підходи

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

Хоч анімація за своєю природою замислювалася, як щось виразне і гнучке, не все так гладко. Те, що анімація, про яку піде мова в статті, стала дуже популярна ще задовго до мого народження злегка пригнічує.

Довговічне чарівність

«Робіть все власними руками, навіть коли використовуєте комп’ютер.» — Хаяо Міядзакі

Студія Гинули Хайо Міядзакі, яка випустила безліч чудових творів, серед яких Віднесені примарами, Ходячий замок і Принцеса Мононоке, дотримується традиційних ручних методів анімації, шаруватої анімації. На відміну від CGI або keyframe анімації за допомогою CSS даний підхід займає набагато більше часу.

Міядзакі також відомий тим, що особисто готує локшину рамен для своїх працівників-аніматорів пізніми ночами, і все заради успіху.

Створення шаруватої анімації на SVG

Проте студія Гинули працює вручну не тому, що це якийсь фетиш минулого. Причина того, що анімаційні роботи не втрачають своєї популярності після винаходу камери в тому, що ви можете поглянути на життя з допомогою пари мазків. Все це застосовно і до анімації, де кожний кадр малюється художником повністю, а не є артефактом векторної графіки. Кінцевий продукт набагато багатшими. Існує негласна традиція малювати вручну, так кожен кадр передає якусь інформацію.

Створення шаруватої анімації на SVG

Ліва, гладка анімація зроблена за допомогою keyframe трансформацій, в той час як в основі правою лежать три незалежних кадру, один за іншим. Користувачі Firefix могли помітити, що для анімації вище не применилось властивість transform-origin, вся справа в ба.

Незручний SMIL

Якщо сказати, що в інтернеті не існує технології для створення веб шаруватої анімації, це буде брехня. Громіздку назву Синхронізований мова мультимедійних інтеграцій (SMIL), ця мова призначена для створення анімації. У Jonathan Ingram є чудовий урок по використанню SMIL для створення шаруватої і зацикленої анімації на прикладі персонажів Mortal Kombat:

Елемент animate використовується для визначення стану анімації для батьківського елемента.

Проте не обходиться і без серйозних проблем. Незважаючи на досить стару класифікацію, SMIL все ж не підтримується IE. Більш того, підтримка також не планується ні в IE12, 15 або навіть у 38. У той же самий час мова застаріває, а підтримка в Chrome падає. Paul Kinlan з Google розповів, що в бета-версії Chrome 45 фактично закрили очі на попередження про старіння SMIL.

Підтримка SMIL продовжує зменшуватися, і я знаходжу небагато дивним використання XML розмітки для створення анімації. Я звик, що моя анімація знаходиться в окремому файлі стилів, і думаю їй там саме місце. Зрештою, анимируя елемент, ми міняємо тільки його візуальне положення, але не зачіпаємо розмітку. Це можна тільки в JavaScript.
На жаль, в CSS немає явного або швидкого способу створення шаруватої анімації, однак я опишу спосіб на основі рідко використовуваних keyframe властивостей CSS.

Почнемо

@keyframe анімація працює за допомогою властивості animation-timing-function, ви повинні знати про деякі тимчасові функції. Наприклад, властивість ease-in зменшує швидкість анімації, коли та підходить до завершення.

Рідко використовувана функція steps() також представляє інтерес для нас, так як вона імітує ефект посмикування, анімація ніби складається з окремих шарів, що програються, один за іншим. Приміром, steps(5) виконає досить плавну анімацію з п’яти окремих шарів.

Всі значення функції steps() імітують keyframe анімацію; немає якогось магічного перемикання кадрів. Але, якщо скористатися steps(1), то можна просто перемикатися між кадрами без будь-якої анімації. Змінюючи властивість opacity від 1 до 0, ми можемо показувати або ховати анимируемый елемент за один крок: ось він є, а ось і ні. Це дуже важливий етап побудови шаруватої анімації, яку я збираюся створити.

Створення шаруватої анімації на SVG

Елементи, як окремі шари

Поки що, мене турбує тільки один елемент, або шар, який сам по собі не робить ніякої анімації і не заслуговує тієї самої локшини Міядзакі. Це коли картинка просто з’являється і зникає.

Для створення повноцінної анімації нам доведеться створити більше зображень: набір шарів, які й будуть складати анімацію. Цей етап дуже довгий і не з легких, але я не буду скаржитися на це: промальовування кожного окремого шару, ось що робить даний тип анімації особливим. Пізніше мені знадобиться допомога з написанням логіки анімації.

Розмітка

Для цього мені знадобиться SVG. Технічно шарів може бути скільки завгодно, але в SVG ми можемо з легкістю визначити набір елементів path і накласти їх один на одного. У прикладі нижче я створив контейнер для анімації з допомогою SVG елемента (група), всередині якого знаходяться наші шари. Дані шари повинні бути прописані в порядку, в якому ви хочете, щоб вони з’являлися.

Створення шарів

Існує безліч графічних редакторів для роботи з SVG, але Inkscape був створений спеціально для роботи з цим форматом, а також включає в себе вбудовану панель редагування XML. Він нам сильно полегшить життя. А ще він безкоштовний. Щоб продемонструвати механіку, швидко пробіжимося по SVG. Створіть новий документ Inkscape і намалюйте три фігури, як на малюнку нижче. Не обов’язково, щоб вони були точно такі ж.

Створення шаруватої анімації на SVG

Додайте всі фігури одна над іншою і підженете розмір документа під розмір фігур. Щоб зробити це, виберіть File->Document Properties а потім Resize page to drawing or selection. Простежте, щоб не була обрана якась окрема фігура, інакше розмір документа буде підібраний під цю конкретну фігуру.

Створення шаруватої анімації на SVG

Потім виберіть всі фігури і клацніть Object->Group, створиться елемент групи . Потім, не знімаючи виділення з групи, відкрийте Edit &-> XML Editor і виберіть групі клас .shapes.

Створення шаруватої анімації на SVG

Чудово, тепер збережіть SVG-файл. Зі списку виберіть Optimized SVG і поставте галочку навпроти Enable viewboxing. Тепер наш SVG повністю готовий до анимированию.

Створення шаруватої анімації на SVG

Зауваження щодо оптимізації

Використовуючи такі прості форми, як у нас, SVG дані зводяться до мінімуму. В даному випадку розмір анімованого SVG (разом з CSS, який ми ще напишемо) буде всього 2.3 Кб. Простіше кажучи, чим простіше фігура на кожному шарі, тим більше шарів можна собі дозволити. Для анимирования більш складних зображень, як каракулі, які ми будемо використовувати у даній статті, я рекомендую використовувати інструмент від Jake Archibald SVGOMG.

Накладання шарів

Як я писав вище за допомогою steps(1) можна перемикати видимість елемента з допомогою непрозорості. Не можна домогтися такого ж ефекту властивість display, так як воно приймає тільки конкретні значення (нічого анімувати). Для початку встановимо всі шари в контейнері в opacity:0.

.shapes > * {
opacity: 0;
animation-duration: 0.75 s;
animation-iteration-count: infinite;
animation-timing-function: steps(1);
}

Як і при налаштуванні системи тимчасових функцій, я вибрав нескінченне число ітерацій, тривалість анімації 0.75 s. Так як кожен кадр відображається на однакову кількість часу, а кадрів у нас три, то кожен кадр повинен з’являтися на 0.25 s, або 4 кадри в секунду.

Отже, як зазначалося, кожен кадр відображається за іншим? Кожному елементу вам необхідно встановити тривалість анімації 0.75 s, а потім запустити всі кадри одночасно, плавно показуючи один поверх іншого. При трьох шарах кожен має бути видно третину часу. Я використовував відсотки (@keyframe синтаксисі) і застосував для кожного nth-child свою анімацію.

@keyframes shape-1 {
0% {
opacity: 1;
}
33.33333% {
opacity: 0;
}
}
.shapes > :nth-child(1) {
animation-name: shapes-1;
}
@keyframes shapes-2 {
33.33333% {
opacity: 1;
}
66.66667% {
opacity: 0;
}
}
.shapes > :nth-child(2) {
animation-name: shapes-2;
}
@keyframes shapes-3 {
66.66667% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.shapes > :nth-child(3) {
animation-name: shapes-3;
}

Створення шаруватої анімації на SVG

Вбудовування і підключення

Тепер, щоб створити мою масштабовану GIF анімацію, я, нарешті, можу додати в SVG-файл стилі. Так як у мене не стоїть на комп’ютері таск раннер, я використовував онлайн версію autoprefixer для автоматичного додавання вендорних префіксів.

Створення шаруватої анімації на SVG

Деякі, але не всі браузери будуть програвати анімацію, навіть якщо підключити SVG через тег img. Більш надійно використовувати object.

Зауважте, що WAI-ARIA роль зі значенням img і атрибут aria-label як для об’єкта (object), так і для елемента DIV використовуються для семантичної точності. Я не став робити фоллбэк для старих браузерів за допомогою img, так як деякі браузери завантажують цей тег в доповненні до SVG. Але вам, звичайно, необхідно додати статичне фонове зображення через CSS властивості background-image для елемента .shapes-fallback.

Одне зображення, багато анімацій

Крім масштабованості в SVG є ще одна перевага над GIF, і це можливість анімувати окремі частини одного зображення – різні швидкості анімації і різна тривалість. В моєму прикладі з акулою хвіст і очі анімуються з різною швидкістю та різною кількістю шарів.

Створення шаруватої анімації на SVG

Математично кажучи, тут відбувається щось цікаве: якщо у вас є дві окремі анімації у складі одного файлу, то загальна тривалість анімації буде більше, ніж у окремих складових. Отже, якщо одна анімація складається з трьох кадрів, а інша з чотирьох, то загальна довжина буде 12 кадрів – в три рази довше, ніж сама тривала з двох окремих анімацій.

В GIF, де кожен кадр безпосередньо пов’язаний з шаром, домогтися такого ефекту можна тільки, додавши нові фотографії. Відповідно і розмір файлу збільшується.

Створення шаруватої анімації на SVG

Змінна анімація

В моєму прикладі shark.svg і хвіст, що виляє, і миготливі очі використовують чередующуюся, симетричну анімацію, де всі верстви програються спочатку вперед, потім назад, і так нескінченно. Кожен елемент шаруватої анімації починає рухатися одночасно, створюючи ефект нескінченної анімації за допомогою властивості animation-direction: alternate для кожного шару:

.tail > * {
animation-direction: alternate;
}

Даний підхід економить вагу. Щоб домогтися такого ж ефекту в GIF, необхідно додати зображення двічі: спочатку у звичайному порядку, потім у зворотному.

По-справжньому шарувата анімація

Я почав свою статтю з висновку, що традиційна шарувата анімація важко порівнянна із сучасної keyframe анімацією. До появи шаруватої анімації кожен кадр малювався повністю – не тільки анимируемая частину зображення. Якщо на шарах малювати тільки анимируемые частини, статичні фони можна використовувати повторно. Крім економії часу такий підхід також підвищує плавність.

Створення шаруватої анімації на SVG

SVG це формат зображень на основі тексту, даний формат ділиться на безліч «піддерев» розмітки. Це робить даний формат ідеальним для об’єднання статичних і анімованих зображень.

Створення шаруватої анімації на SVG

Автоматизація за допомогою Sass

Моя анімація стає все більш гострою, а створення окремих класів анімацій для кожного шару злегка втомлює. Для виконання важкої роботи я підключив Sass. За допомогою директиви @for та деяких обчислень мені вдалося створити анімацію автоматично:

$cels: 6;
$fraction: 100 / $cels;
@for $i from 1 through $cels {
$name: shapes;
$start: ($fraction * $i) — $fraction;
@keyframes #{$name}-#{$i -} {
#{$start * 1%} {
opacity: 1;
}
#{($start + $fraction) * 1%} {
opacity: 0;
}
}
> :nth-child(#{$i}) {
animation-name: #{$name}-#{$i};
}
}

Зверніть увагу, що я використовував рядок «shapes» і вставляв її на кожній ітерації для створення іменованих класів анімації: @keyframes shapes-1 {}. Потім цей код я включив у міксин і створив імена динамічно, додавши унікальний ідентифікатор за допомогою unique-id().

$name: unique-id();

В наступному прикладі, де параметр 3 це кількість шарів, для динамічного створення іменованих анімацій використовуються унікальні рядки cel-u358d90ae, cel-uebf9a21c і cel-u05cf8ffe.

.shapes {
@include cel-animation(3);
}

Покращуємо керованість

Все, що я робив вище, стало вже більш очевидним. Кожен шар повинен бути видний однаковий час. У випадках, як з моєї акулою, потрібно зробити так, щоб шари, коли око відкритий, тривали довше, ніж шари, які відповідають за миготливий очей. >

Спочатку я просто продублював шари з відкритим оком, додавши 6 однакових зображень, імітуючи паузу. Але мені не сподобався ефект: це було вкрай громіздко, а також збільшився вага файлу. Зрештою, мені потрібен був спосіб, з допомогою якого можна було домогтися одночасного встановлення кількості шарів та їх тривалості: двовимірний параметр. Виходом послужив Sass список.

.eyes {
@include frame-animation((6 1 1 1), 0.15);
}

В даному прикладі, який генерує миготливий очей акули, перший параметр $cels задає список шарів, причому перший шар відображається в шість разів довше, ніж інші. Кількість шарів можна отримати за допомогою length($cels), а для отримання кількості кадрів необхідно додати цілочисельне значення до кожного шару в списку. Другий параметр-швидкість кадру 0.15, тривалість анімації буде розрахована як (6+1+1+1)*0.15*1s.

Доведена до розуму версія даного міксина доступна на GitHub. Насолоджуйтесь і не забувайте надсилати мені свої роботи. Я б хотів їх включити в невелику демонстрацію, ваші дані, природно, будуть вказані!

Висновок

Як дизайнер, я не люблю копирсатися в коді. Мене не приваблюють технології, якщо вони не вирішують фундаментальних проблем. Тому я сам розробив свій спосіб і написав під нього код, так як я дійсно хотів створити шарувату анімацію з моїх малюнків. Мета була поставлена. Хоча і є деякі речі, яких не знайти в інтернеті (а деякі виглядають набагато простіше, ніж повинні), іноді, краще самому придумати свій «масив» технологій, який задовольнить вашим завданням. З точки зору дизайну важливо визначити, що ми хочемо зробити в першу чергу, для кого ми хочемо це зробити і гідна це ідея.