book-open 1 test
Анимация интерфейсов

Анимированный лого средствами JavaScript

Используем Clip-Path, чтобы сделать анимации еще красивее

Вы читаете перевод статьи Нейтана ГордонаMasking SVG Animations”. Над переводом работали: Анастасия Свеженцева и Ольга Жолудова. При поддержке iSpring.

iSpring — решение для запуска дистанционного обучения.

Если вы, так же как и я, начинаете уставать от идеально-линейных SVG анимаций, волна которых сейчас проносится по всему интернету, добавляйте этот небольшой трюк в свой арсенал и подходите к вопросу творчески!

Интересуетесь свежими статьями по продуктовому дизайну (UX/UI)? 🚀

Подписывайтесь на канал в Telegram | ВКонтакте, Instagram, Facebook

Вот посмотрите на эту анимацию в стиле loony tunes в действии на одном из сайтов ultranoir — “Over The Hills”.

Такой эффект обычно достигается посредством последовательности картинок, но тот факт, что в данном случае это SVG, дает мне ряд преимуществ:

  1. Я с легкостью дублировал анимацию и поменял ее цвет, чтобы создать тень — а потом анимировал масштаб и расположение каждой анимации по-отдельности;
  2. Мне не пришлось загружать кучу спрайтов анимации, как и не пришлось создавать петлю
  3. Если приходилось вносить какие-либо изменения, я вносил их прямо в код, а невероятно точную синхронизацию обеспечила анимационная библиотека Greensock
  4. И, наконец, мне удалось соединить на одной временной шкале эту анимированную линию и со всеми остальными анимациями, что обеспечило мне полный контроль над воспроизведением.

На деле все очень просто: мы добавляем маску к уже существующим SVG анимациям. Давайте рассмотрим детали:

Шаг 1: Создаем ресурсы

Это очень и очень важный шаг — если вы никак не можете приступить к работе, скорее всего, причина в том, что вы неправильно экспортировали ресурсы SVG.

Начните с создания формы маски. Эта та область, которая останется видимой, когда анимация завершится. Я использовал Illustrator, поэтому буду ссылаться на него, но я уверен, что любая программа, работающая с вектором, подойдет.

Прежде, чем экспортировать вашу маску, стоит соединить все части в один единственный путь. Для этого, используйте boolean (логические) операции в pathfinder или, если части расположены отдельно, создайте составной путь (compound path) в меню Объект (Object). Если вы на этом застряли, вот небольшое объяснение от Adobe.

Потом нарисуйте ваши пути поверх маски: делайте их шириной в штрих (достаточно широкий, чтобы закрыть маску). Эти линии мы и будем анимировать, но видны они будут только в пределах маски, создавая иллюзию, что анимируется сама маска.

Теперь наш пример покрыт линиями. В данном случае у меня 8 отдельных путей — и я следил, чтобы линии не показывали те пути маски, которые не нужно показывать. Это бы разрушило иллюзию. Если в вашем случае существует такая проблема, возможно, придется разбить анимацию на большее количество линий, или даже создать несколько отдельных масок, каждую со своими линиями. Конечно, придется потрудиться и правильно все расположить, чтобы анимация работала идеально!

Чтобы показать, что я имею в виду, я создал простой пример. Вот случай, когда линия пересекает сама себя — она попутно показывает ту часть маски, которую еще рано показывать.

Если бы это сильно бесило меня, я бы просто разделил анимацию на две части, тем самым избежав пересечения линий.

Шаг 2: Форматируем SVG код

Как только вы закончите работу над путями и маской, экспортируйте их в виде SVG кода. Я не буду показывать код того сложного примера с Dead Pirates, потому что он слишком длинный. Вот вам пример попроще:

<?xml version=”1.0" encoding=”utf-8"?>
<! — Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) →
<!DOCTYPE svg PUBLIC “-//W3C//DTD SVG 1.1//EN” “http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version=”1.1" xmlns=”http://www.w3.org/2000/svg" x=”0px” y=”0px” width=”100px” height=”100px” viewBox=”0 0 100 100">
    <path d=”M48.28,7.333v82.838c0,1.381–1.117,2.496–2.495,2.496H14.762c-1.379,0–2.499–1.115–2.499–2.496V7.333H25.64v72.029h9.268V7.333H48.28z M65.1,92.667V20.64h9.265v72.027h13.374V9.83c0–1.379–1.117–2.497–2.497–2.497H54.219c-1.379,0–2.497,1.118–2.497,2.497v82.837H65.1z”/>
    <path fill=”none” stroke=”#000000" stroke-width=”20" d=”M18.5,7c0,0,0,68.5,0,75.5s22.75,7,22.75,0C41.417,56.5,41.301,7,41.301,7"/>
    <path fill=”none” stroke=”#000000" stroke-width=”20" d=”M81.5,93c0,0,0–68.5,0–75.5s-22.91–7–22.91,0c-0.166,26,0.029,75.5,0.029,75.5"/>
</svg>

Не самый чистый код для работы, но присмотритесь — и вы увидите один путь с кучей данных и два небольших пути, к которым применен параметр stroke (штрих). Возможно, вы уже догадались, что первый путь станет маской, а остальные пути будут анимироваться. Осталось объяснить это все компьютеру.

Внутри SVG мы создадим тег <defs>. Потом вставим тег <clipPath> с id “myClip” . Расставим эти теги вокруг пути маски. Оказавшись внутри этих тегов, путь маски станет невидимым.

Потом мы добавим атрибут ‘clip-path’ к анимирующимся путям со значением ‘url(#myClip)’, тем самым связав их с обрезающим путем (clip path) c id “myClip”, который мы только что создали.

Вот примерчик с пылу с жару:

<svg version=”1.1" xmlns=”http://www.w3.org/2000/svg" x=”0px” y=”0px” width=”100px” height=”100px” viewBox=”0 0 100 100">
<defs>
<clipPath id=”myClip”>
<path d=”M48.28,7.333v82.838c0,1.381–1.117,2.496–2.495,2.496H14.762c-1.379,0–2.499–1.115–2.499–2.496V7.333H25.64v72.029h9.268V7.333H48.28z M65.1,92.667V20.64h9.265v72.027h13.374V9.83c0–1.379–1.117–2.497–2.497–2.497H54.219c-1.379,0–2.497,1.118–2.497,2.497v82.837H65.1z”/>
</clipPath>
</defs>
<path clip-path=”url(#myClip)” fill=”none” stroke=”#000000" stroke-width=”20" d=”M18.5,7c0,0,0,68.5,0,75.5s22.75,7,22.75,0C41.417,56.5,41.301,7,41.301,7"/>
<path clip-path=”url(#myClip)” fill=”none” stroke=”#000000" stroke-width=”20" d=”M81.5,93c0,0,0–68.5,0–75.5s-22.91–7–22.91,0c-0.166,26,0.029,75.5,0.029,75.5"/>
</svg>

Можете вставить этот код прямо в HTML.

Шаг 3: Анимируем при помощи javascript

А теперь покроем торт кремом. Я буду использовать библиотеку Greensock TweenMax, а также старую добрую jQuery. Что касается анимации, в ее основе лежит маленький гениальный трюк, который Крис Койер представил миру в своей знаменитой статье. Суть трюка в том, что для достижения эффекта рисования линии “от руки” нужно анимировать только атрибут stroke-dashoffset. Пожалуйста почитайте статью, если еще не читали — она крутая и объясняет вещи, которые сложно объяснить.

Во-первых, мы сохраняем ссылку на наши пути (кроме обрезающего пути, который находится внутри тега ‘defs’).

var paths = $(‘path:not(defs path)’);

Потом для каждого пути мы устанавливаем значения stroke-dasharray и stroke-dashoffset равными полной длине пути, таким образам оставляя их невидимыми (если что-то непонятно, прочитайте статью про CSS трюк. Я серьезно).

paths.each(function(i, e) {
    e.style.strokeDasharray = e.style.strokeDashoffset = e.getTotalLength();
});

Создадим временную шкалу Greensock для удобства управления и чтобы иметь возможность проигрывать анимацию туда-сюда на нужной скорости.

var tl = new TimelineMax();

Добавим каждый отдельный путь анимации на временную шкалу, анимируя атрибут stroke-dashoffset до нулевого значения. Чтобы добиться идеального воспроизведения анимации, поэкспериментируйте с продолжительностью (duration), задержкой (delay) и смягчением (easing).

tl.add([
    TweenLite.to(paths.eq(0), 1, {strokeDashoffset: 0, delay: 0.0}),
    TweenLite.to(paths.eq(1), 1, {strokeDashoffset: 0, delay: 0.5}),
]);

А теперь смотрите, как в браузере происходит магия! Вы можете скачать весь пример здесь.

Имейте в виду, что того же эффекта можно было добиться с использованием чистых CSS анимаций или кастомной анимациии requestAnimationFrame — я просто предпочитаю пользоваться TimelineMax, поскольку это крутая штука, которая позволяет мне добиться максимально чистого кода, при том, что каждый элемент находится под моим абсолютным контролем. Многое зависит от контекста ситуации: в случае с ‘Over The Hills’ моя анимация была частью огромного анимированного вступления, поэтому выполнить ее именно так было вполне очевидным решением.

Надеюсь, что у вас получится воспользоваться этим небольшим трюком, и ваша мама будет вами гордиться!