ДизайнУха
26
Sep

Три способа повторения анимации: Sass, GSAP и Web Animations API

источникcss-tricks.com
авторOpher Vishnia

Согласно Олли Джонстону и Фрэнку Томасу («Иллюзия жизни», 1981), пошаговая анимация, известная также как «доведение действия до конца» или «перекрытие действия», является одним из двенадцати анимационных принципов компании Disney. Суть принципа заключается в том, что анимационные объекты воспроизводятся в замедленной последовательности, и таким образом получается плавное действие.

Однако данная техника применяется не только при анимировании мультяшных героев. Проблема моушн-дизайна пользовательских интерфейсов тесно связана с UX, а также с пользовательским восприятием и «ощущениями». Компания Google уделяет этой теме особое внимание в разделе моушн-хореографии, входящего в гид по материальному дизайну.

Учитывая тот факт, что тема моушн-дизайна весьма многообразна, мне часто приходится даже в самых небольших проектах уделять большое внимание мелочам. Во время работы над дизайном рекламы Interactive Coke для компании Eko у меня было задание разработать анимацию, которая имитировала бы загрузку интерактивного видео, и вот что получилось:

На первый взгляд кажется, что нет ничего проще, чем сделать такое в CSS. Но оказалось, что это не тот случай, и гораздо проще будет создать подобную анимацию с помощью GSAP или воспользоваться новеньким Web Animations API. Для того чтобы сделать то же самое в CSS, нужно знать некоторые уловки, о которых я и планирую рассказать в этой статье. Но зачем вообще так заморачиваться и использовать именно CSS? В нашем случае причина в том, что анимация крутится, пока пользователь ждет, когда загрузится основная часть. Поэтому нет никакого смысла создавать целую анимационную библиотеку ради одного значка загрузки.

Вначале давайте разберемся со структурой анимации

У нас есть четыре абсолютно позиционированные окружности внутри контейнера с overflow: скрытый, что позволяет ограничить анимацию и обрезать боковые окружности. Почему же их четыре, а не три? Когда последняя — правая — окружность уходит за кадр, слева появляется вторая окружность. Две другие всегда остаются в пределах кадра. Таким образом, конец анимации выглядит как ее повторение с самого начала. Первый круг встает на место второго, второй — на место третьего, и т.д.

Вот стандартный HTML:

И последующий CSS:

Давайте опробуем это на простой анимации, где каждая окружность двигается по оси X от 0 до 60 пикселей:

See the Pen dot loader — no stagger by Opher Vishnia (@OpherV) on CodePen.

Выглядит немного странно и как-то механично, не правда ли? Все потому, что у нас не хватает одного важного компонента: пошаговой анимации. Анимация каждой последующей окружности должна начинаться с небольшим опозданием. «Да это не проблема!» — подумаете вы, -«Можно просто использовать функцию animation-delay. Мы дадим четвертому кругу значение 0, третьему — 0.15сек, и т.д.». Ну давайте попробуем:

See the Pen dot loader — broken by Opher Vishnia (@OpherV) on CodePen.

Так... и что же вышло? Задержка анимации действует только вначале, перед тем, как начинается анимация. Между остальными же компонентами отступы остаются прежними, что приводит к сбою анимации. Например, как на этой диаграмме:

Спасительная математика

Чтобы такого не произошло, я вставил задержку в саму анимацию. Анимации CSS с ключевыми кадрами оформляются в процентах, и немного поиграв с цифрами, можно установить процент задержки анимации. Например, если анимация длится 1сек, вы можете установить начальный ключ на 0%, те же значения на 20%, а затем конечный ключ на 80% и те же конечные значения на 100%. Ваша анимация задержится на 0.2сек, будет длиться 0.6сек, и затем приостановится еще на 0.2сек.

К примеру, я хотел, чтобы каждая окружность задерживалась на 0.15сек прежде чем начиналась сама анимация, которая длилась 0.5сек. Весь же процесс занимал 1сек. Это значит, что анимация четвертой окружности не задерживается вообще, затем появляется на 0.5сек и задерживается еще на 0.5сек. Вторая окружность задерживается на 0.15сек, затем также появляется на 0.5сек и снова задерживается, но уже на 0.35сек, и т.д.

Чтобы этого добиться, вам понадобятся четыре ключевых кадра (или три пары ключевых кадров): 1 и 2 отвечают за начальную задержку, 2 и 3 — за длительность анимации, а 3 и 4 — за конечную задержку. Хитрость заключается в том, что нужно понимать, как именно преобразовать нужные временные отрезки в ключевые проценты, но на самом деле это достаточно легко. Например, задержка второй окружности должна составлять 0.15*2=0.3сек, а длительность анимации — 0.5сек. Так как я знаю, что все время анимации равно 1сек, я рассчитываю проценты таким образом:

0сек = 0%
0.3сек = 0.3 / 1сек * 100 = 30%
0.8сек = (0.3 + 0.5) / 1сек * 100 = 80%
1сек = 100%

Конечный результат выглядит примерно так:

Так что если вся анимация (включая задержку, встроенную в ключевые кадры CSS) будет занимать одну секунду, никакого сбоя не будет.

К счастью, модуль Sass позволит автоматизировать этот процесс с помощью простого циклирования и небольших математических вычислений, что в конечном итоге превратится в серию ключевых анимаций. Чтобы посмотреть, как лучше будет выглядеть анимация, вы можете поэкспериментировать с временными отрезками:

И вот что мы в итоге получили:

See the Pen dot loading animation — SASS stagger by Opher Vishnia (@OpherV) on CodePen.

Но, используя этот метод, вы должны знать две важные вещи:

Во-первых, устанавливая время задержки/анимации, убедитесь, что оно не превосходит время всей анимации, иначе возникнет ошибка вследствие математических просчетов.

Во-вторых, при использовании данного метода генерируется просто огромное количество CSS кода, особенно если вы прибегаете к Sass для совместимости анимации с любым браузером. В моем случае было всего 4 анимируемых объекта, но если у вас объектов будет больше, возможно, вы просто потратите впустую много сил, чтобы сгенерировать весь этот код. Возможно, вы даже захотите перейти к анимационным библиотекам, основанным на Java Script (например, GSAP). Но, все же, по-моему, круче, когда вся анимация создана в CSS.

Упрощаем себе жизнь

Но вы, наверное, уже устали от большого количества букв, поэтому я хотел бы показать, как того же самого результата можно добиться с помощью GSAP Timeline и функции staggerTo:

Здесь есть два интересных момента. Во-первых, последний параметр функции, обозначающий время задержки между анимационными объектами, имеет отрицательное значение (-0,15). Такая фишка позволяет объектам задерживаться в обратном порядке (окружности 4-3-2-1 вместо 1-2-3-4). Классно, правда?

See the Pen dot loading animation — GSAP by Opher Vishnia (@OpherV) on CodePen.

Теперь о втором моменте. Видите код, где написано tl.set({}, {}, «1»);? «Что это вообще такое?» — спросите вы. А это аккуратненький хак, который осуществляет задержку в конце анимации каждой окружности. По сути, если пустой объект установлен на время 1, анимация Timeline будет повторяться после каждой отметки «1», а не после окончания анимации предыдущей окружности.

С нетерпением ждем будущего

Web Animations API — это новый потрясающий плагин, но про него мы поговорим как-нибудь в другой раз. Тем не менее, я не мог не показать вам пример создания простой анимации с его помощью. Заметьте, что здесь используются точно такие же математические вычисления, как и в случае создания анимации в CSS:

See the Pen dot loading animation — WAAPI by Opher Vishnia (@OpherV) on CodePen.