Трюки с CSS-анимациями: мгновенные изменения, отрицательные задержки, анимация transform-origin и другое

Источник: habrahabr
ilya42

Применяя CSS-анимации в повседневной работе, я постепенно выработал привычку экспериментировать с ними в свободное время. Постоянно пытаясь реализовать очередную интересную задумку с использованием как можно меньшего числа элементов HTML, я обнаружил немало способов сделать с помощью CSS довольно неочевидные вещи. В этой статье я хочу поделиться некоторыми из них.

Быстрое изменение состояния посреди анимации

Обычно анимации используются для того, чтобы плавно менять свойства элементов со временем. Однако изменения могут также быть практически мгновенными. Для этого надо задать два ключевых кадра с очень маленьким интервалом, например в 0.001%:

@keyframes toggleOpacity { 50% { opacity: 1; } /* Turn off */ 50.001% { opacity: 0.4; } /* Keep off state for a short period */ 52.999% { opacity: 0.4; } /* Turn back on */ 53% { opacity: 1; } }
Вот как я использовал этот приём для имитации мигающей неоновой вывески с помощью прозрачности и свойства text-shadow:



Код примера:

Демо на Codepen

Отрицательные задержки анимации

Положительная задержка откладывает начало анимации на некоторое время. А отрицательная - начинает анимацию немедленно, но не с самого сначала, а со времени, указанного в задержке. Другими словами, начинает анимацию с какого-то момента внутри её цикла. Это позволяет применять анимацию к нескольким элементам со сдвигом фазы, изменяя лишь время задержки. Вот пример использования такой анимации:

Код примера:

Демо на Codepen

Пропорциональные анимации

Я стараюсь делать веб-приложения настолько адаптивными, насколько возможно. Это касается и CSS-анимаций. Хотя сделать абсолютно все анимации адаптивными невозможно, иногда всё же удаётся использовать вместо абсолютных единиц измерения проценты и другие относительные единицы.

Во многих своих анимациях я использую элементы, размеры которых должны быть пропорциональны размерам страницы. Возможно вы думаете, что для этого я использую фиксированную ширину и высоту, но это не так. Можно указать ширину в процентах, нулевую высоту и процентное значение для padding. С помощью padding-bottom высота элементов остаётся пропорциональной ширине:

.container { position: relative; display: block; width: 100%; height: 0; padding-bottom: 100%; }
Если вы откроете следующий пример на Codepen и попробуете изменить размеры окна, вы увидите как это работает. В этом примере также использованы отрицательные задержки анимации.

Код примера:

Демо на Codepen

Изменение transform-origin посреди анимации

Работая над одной из анимаций, я с удивлением обнаружил, что свойство transform-origin не только может меняться посреди анимации, но и само по себе может быть анимировано. В следующем примере это используется для того, чтобы в одной анимации делать четыре разных поворота вместо того, чтобы создавать четыре отдельные анимации:

Код примера:

Демо на Codepen

У этого трюка есть недостаток: вы не можете использовать animation-mode: forwards; только для части анимации. Это значит, что нам придется передвигать элемент при каждом изменении transform-origin. В этом примере translate используется для имитации эффектов поворота. В более сложных примерах это может оказаться довольно утомительным.

Отрицательный transform-origin

Можно задать отрицательное значение transform-origin, что может быть полезно для создания вращающихся элементов. Вместо того, чтобы отдельно задавать смещение и угол поворота для элемента, как описывает Ли Веру, этого можно добиться проще, используя отрицательные значения transform-origin и дополнительный элемент или псевдоэлемент (или только один элемент, если он не обязан сохранять постоянный угол относительно горизонта). С разными значениями transform-origin можно использовать одну и ту же анимацию для разных элементов:

Код примера:

Демо на Codepen

Магия box-shadow

Для анимации простых форм без контента внутри может пригодиться свойство box-shadow. С его помощью можно создавать несколько границ вокруг одного элемента. На основе этой идеи, используя разные смещения для теней, можно создавать целые наборы анимированных фигур на основе одного элемента HTML. Вот пример анимации, которая выглядит, как шесть вращающихся кружков, которые целиком сделаны с помощью box-shadow:

Код примера:

Демо на Codepen

К сожалению, box-shadow не поддерживает относительные размеры в процентах, так что их труднее сделать адаптивными, чем обычные элементы. Тем не менее, их размеры можно менять вручную или применяя transform:scale(n) для родительского элемента.

Использование псевдоэлементов

Так же как и box-shadow, псевдоэлементы можно использовать для обогащения внешнего вида элементов HTML. Для них можно использовать отдельные от родительского элемента анимации, они могут иметь отдельные тени - практически как настоящие элементы. Это позволяет делать удивительные вещи:

Код примера:

Демо на Codepen

В этом примере все концентрические окружности вокруг центрального мигающего круга, так же как и два маленьких кружка на внешнем кольце сделаны с помощью box-shadow. Другие два кружка - это тени псевдоэлемента, а кольцо из штрихов - это фон ещё одного псевдоэлемента, заданный в виде inline SVG.

Несколько советов напоследок

Используйте трансформации везде, где только можно

Как показал Пол Айриш и другие, трансформации работают быстрее, чем изменение размеров и положения элементов с помощью свойст top, left, width и height.

С помощью трансформаций легче реализовать адаптивный дизайн, применяя относительные значения для scale (пример).

Отказ от использования трансформаций приводит к появлению ошибок, которые трудно отловить. Например, вот эта анимация отображается в браузере Chrome с некорректными цветами, хотя значения в коде правильные. После перехода на CSS-трансформации проблема решилась сама собой.

z-index может вызывать проблемы

Пожалуй, на решение проблем с z-index я потратил больше времени, чем на любые другие. Реализация z-index разнится от браузера к браузеру. Главное различие - Mozilla не анимирует z-index, и его значение изменяется скачкообразно, тогда браузеры на основе Webkit умеют изменять его плавно.

Также стоит отметить, что если вам нужно, чтобы псевдоэлементы оказались за родительским элементом, псевдоэлемент должен иметь отрицательный z-index, а родительский элемент при этом обязан располагаться в контексте наложения на месте по умолчанию, то есть к нему нельзя применять z-index или любые другие приёмы, которые вырывают его из стандартного положения в контексте.

И последнее. Любой элемент, для которого задана прозрачность, отличная от "1", получает собственный контекст наложения. Подробнее об этом - в статье Филипа Уолтона.

Ищите источники вдохновения

Что-то в реальном мире, интересная веб-страница, необычный видеоэффект, анимированный gif или что угодно ещё - постоянно ищите вещи, которые стоит попробовать реализовать.

Я обнаружил, что если не подглядывать сразу, как именно сделан тот или иной эффект, можно найти уникальный способ и даже превзойти оригинал. Даже если я терплю неудачу, я всегда по крайней мере узнаю что-то новое о языке программирования, который я использую. Часто получается так, что даже не реализованная полностью задумка оказывается довольно эффектной. Иногда наоборот - результат оказывается намного лучше, чем я мог мечтать.

Надеюсь, что эта статья поможет и вам создать что-то новое и прекрасное, даже многие конкретные техники, описанные в ней, вам уже знакомы.


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=35665