Как создать сложную анимацию на CSS

alexei30/01/2023 - 09:24
Как создать сложную анимацию на CSS

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

Мы ежедневно просматриваем веб-страницы, и как разработчики, склонны замечать тонкие детали на веб-сайте. При этом самое заметное, что сильнее всего привлекает внимание, это то, насколько плавны анимации. Анимация отлично подходит для того, чтобы оживить пользовательский интерфейс и дизайн сайта в общем. Так, можно создать интерактивный веб-сайт, который привлечет внимание посетителей и надолго останется у них в памяти.

На первый взгляд кажется, что создание достаточно комплексных анимаций по силам только опытным специалистам. Но хорошая новость заключается в том, что в CSS можно объединять несколько простых анимаций, создавая тем самым более сложную!

В этой статье вы узнаете:

  • Что такое кривые Безье, и как их можно использовать для создания "сложной" анимации всего в одной строке CSS;
  • Как объединять анимации, чтобы создать более сложную анимацию;
  • Как создать анимацию американских горок, используя изученный материал.

Кривая Безье: Что это такое?

Функция cubic-bezier в CSS - это функция плавности (easing), которая дает вам полный контроль над тем, как ваша анимация будет вести себя с течением времени. Вот официальное определение:

Кубическая Безье - это тип функции плавности, определяемая четырьмя действительными числами, которые задают две контрольные точки P1 и P2 кубической кривой Безье, конечные точки P0 и P3, которые зафиксированы в (0, 0) и (1, 1) соответственно. Координаты по оси х точек P1 и P2 ограничены диапазоном [0, 1].

Кубическая кривая Безье
Кубическая кривая Безье

Но что такое функция плавности?

ДАВАЙТЕ НАЧНЕМ С ЛИНЕЙНОЙ КРИВОЙ

Представьте себе две точки P0 и P1, где P0 - начальная точка анимации, а P1 - конечная. Теперь представьте другую точку, линейно перемещающуюся между этими двумя точками следующим образом:

Анимация линейной кривой Безье
Анимация линейной кривой Безье

Это называется линейной кривой! Это самая простая анимация, и вы, вероятно, использовали ее раньше, когда начинали изучать CSS.

ДАЛЕЕ: КВАДРАТИЧНАЯ КРИВАЯ БЕЗЬЕ

Теперь, представьте, что у вас есть три точки: P0, P1 и P2. Вы хотите, чтобы анимация двигалась от точки P0 в точку P2. В этом случае P1 является контрольной точкой, которая управляет кривой анимации.

Построение квадратичной кривой Безье
Построение квадратичной кривой Безье

Идея квадратичной кривой Безье заключается в следующем:

  1. Соедините воображаемыми линиями точки P0 и P1 и точки P1 и P2 (представлены серыми линиями).
  2. Точка Q0 перемещается по линии между точками P0 и P1. В то же время точка Q1 перемещается по линии между точками P1 и P2.
  3. Соедините воображаемой линией точки Q0 и Q1 (зеленая линия).
  4. В то время, как начинают двигаться точки Q0 и Q1, вдоль зеленой линии начинает двигаться точка B. Путь, по которому проходит точка B, и есть путь анимации.
Анимация квадратичной кривой Безье
Анимация квадратичной кривой Безье, t в [0,1]

Обратите внимание, что точки Q1, Q2 и B не движутся с одинаковой скоростью. Их движение должно начинаться одновременно и заканчиваться в одно и то же время. Таким образом, каждая точка движется с соответствующей скоростью в зависимости от длины линии, по которой она движется.

НАКОНЕЦ: КУБИЧЕСКАЯ КРИВАЯ БЕЗЬЕ

Кубическая кривая Безье состоит из 4 точек: P0, P1, P2 и P3. Анимация начинается в точке P0 и заканчивается в точке P3. Точки P1 и P2 - контрольные.

Построение кубической кривой Безье
Построение кубической кривой Безье

Кубическая кривая Безье работает следующим образом:

  1. Нарисуйте воображаемые линии на отрезках (P0, P1), (P1, P2) и (P2, P3). Представлены серыми линиями.
  2. Точки Q0, Q1 и Q2 перемещаются по линиям (P0, P1), (P1, P2) и (P2, P3) соответственно.
  3. Нарисуйте воображаемые линии на отрезках (Q0, Q1) и (Q1, Q2). Зеленые линии.
  4. Точки R0 и R1 перемещаются по линиям (Q0, Q1) и (Q1, Q2) соответственно.
  5. Нарисуйте линию между точками R0 и R1. Синяя линия.
  6. Наконец, точка B перемещается вдоль линии, соединяющей точки R0 и R1. Это и есть путь анимации.
Анимация кубической кривой Безье
Анимация кубической кривой Безье, t в [0,1]

Сложение анимаций

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

Например:


animation: movePointLeft 4s linear forwards, movePointDown 3s linear forwards;

Здесь у нас есть две анимации: movePointLeft и movePointDown. Задержка анимации movePointLeft будет равна нулю, потому что это анимация, которая запускается первой. Задержка же анимации movePointDown составит четыре секунды, потому что столько длится анимацция movePointLeft.

Таким образом, мы получаем следующие значения свойства animation-delay:


animation-delay: 0s, 4s;

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

Например:


animation: x 4s linear forwards, y 4s linear forwards, jump 2s linear forwards;

Предположим, мы хотим, чтобы анимации x и y начинались одновременно. В этом случае задержка для этих двух анимаций будет равна нулю, в то время как задержка для анимации jump составит четыре секунды (а не восемь!).


animation-delay: 0s, 0s, 4s;

Создание анимации американских горок

Теперь, когда у нас есть все базовые знания, пора применить их на практике!

ПОНИМАНИЕ АНИМАЦИИ

Траектория американских горок состоит из трех частей:

  1. Скольжение (The sliding part),
  2. Петля (The loop part),
  3. И небольшая анимация горизонтального прохода между первыми двумя анимациями и в конце.
Траектория американских горок
Траектория американских горок

ПОДГОТОВКА

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

1. Добавьте следующий код в тело вашего нового HTML файла:


<div id="the-cart" class="cart"></div>

2. Добавьте следующий код в ваш CSS файл:


.cart {
  background-color: rgb(100, 210, 128);
  height: 50px;
  width: 50px;
  border: 1px solid black;
  border-radius: 50px;
  position: absolute;
  left: 10vw;
  top: 30vh;
}

Чтобы сделать анимацию адаптивной, мы будем использовать единицы ширины (vw) и высоты (vh) окна просмотра. Вы же можете использовать любые единицы измерения.

СКОЛЬЖЕНИЕ

Ту часть, в которой наш шар-тележка скользит вниз и вверх, можно реализовать с помощью функции cubic-bezier! Анимация будет состоять из 2 частей, первая часть - анимация вдоль оси х, вторая - вдоль оси y. Анимация по оси х - это обычная линейная анимация по горизонтали. Определим ее ключевые кадры следующим образом:


@keyframes x {
  to {
    left: 40vw;
  }
}

Добавим ее в свойство animation в траектории шара:


animation: x 4s linear forwards

Вторая часть анимации скольжения - анимация по оси y. Именно здесь мы будем использовать функцию cubic-bezier. Давайте сначала определим ключевые кадры анимации. Мы хотим, чтобы разница между начальной и конечной точками была настолько маленькой, чтобы шар после провала достигал почти той же высоты.


@keyframes y {
  to {
    top: 29.99vh;
  }
}

Теперь подумаем о функции cubic-bezier. Нам нужно, чтобы сначала шарик медленно двигался вправо, а затем, когда он соскальзывает вниз, покатился быстрее.

Функция cubic-bezier
Функция cubic-bezier
  • Медленное движение вправо означает, что P1 будет идти вдоль оси x. Таким образом, мы получаем позицию (V, 0).
    • Нам нужно выбрать подходящее значение V, которое заставит наш шар медленно двигаться вправо, но не слишком далеко, чтобы он не прошел все пространство. В нашем случае значение 0.55 подходит лучше всего.
  • Для достижения эффекта скольжения вниз нам нужно переместить P2 вниз по оси y, т. е. задать отрицательное значение. Таким образом, P2 = (X, -Y).
    • Y должно иметь большое значение. В данном случае мы выбрали Y=5000.
    • Что касается X. Мы знаем, что скорость анимации должна быть выше при скольжении вниз и медленнее при подъеме. Таким образом, чем ближе X к нулю, тем будет круче угол анимация при скольжении вниз. В данном случае зададим X = 0.8.

Теперь мы можем задать функцию cubic-bezier. Она будет cubic-bezier(0.55, 0, 0.2, -800).

Давайте добавим ключевые кадры в наше свойство animation:


animation: x 4s linear forwards,
                  y 4s cubic-bezier(0.55, 0, 0.2, -5000) forwards;

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


animation-delay: 0s, 0s;

ДОБАВЛЯЕМ ГОРИЗОНТАЛЬНЫЙ ПРОХОД

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

Определим ключевые кадры:


@keyframes x2 {
  to {
    left: 50vw;
  }
}

Добавим это в свойство animation:


animation: x 4s linear forwards,
                  y 4s cubic-bezier(0.55, 0, 0.2, -5000) forwards,
                  x2 0.5s linear forwards;

Эта анимация должна начинаться после анимации скольжения, а анимация скольжения занимает четыре секунды; таким образом, задержка составит четыре секунды:


animation-delay: 0s, 0s, 4s;

ПЕТЛЯ

Чтобы в CSS создать круг (петлю), нам нужно переместить круг в центр петли и запустить анимацию оттуда. Мы хотим, чтобы радиус окружности был 100px, поэтому мы изменим положение окружности на top: 20vh (30 - желаемый радиус (здесь 10vh)). Однако это должно произойти после завершения анимации скольжения, поэтому мы создадим другую анимацию с нулевой продолжительностью и добавим подходящую задержку.

Создаем ключевые кадры:


@keyframes pointOfCircle {
  to {
    top: 20vh;
  }
}

Добавляем в список анимаций с продолжительностью 0s:


animation: x 4s linear forwards,
                  y 4s cubic-bezier(0.55, 0, 0.2, -5000) forwards,
                  x2 0.5s linear forwards,
                  pointOfCircle 0s linear forwards;

Добавляем задержку, которая должна составлять 4.5s:


animation-delay: 0s, 0s, 4s, 4.5s;

Сама петля

Чтобы создать анимацию петли:

Создаем ключевой кадр, который перемещает шар обратно на старое положение, а затем поворачивает его:


@keyframes loop {
  from {
    transform: rotate(0deg) translateY(10vh) rotate(0deg);
  }
  to {
    transform: rotate(-360deg) translateY(10vh) rotate(360deg);
  }
}

Добавляем анимацию в свойство animation:


animation: x 4s linear forwards,
                  y 4s cubic-bezier(0.55, 0, 0.2, -5000) forwards,
                  x2 0.5s linear forwards,
                  pointOfCircle 0s linear forwards,
                  loop 3s linear forwards;

Добавляем задержку, которая также должна составлять 4.5s:


animation-delay: 0s, 0s, 4s, 4.5s, 4.5s;

ДОБАВЛЯЕМ ГОРИЗОНТАЛЬНЫЙ ПРОХОД (ЕЩЕ РАЗ)

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

Добавляем ключевые кадры:


@keyframes x3 {
  to {
    left: 70vw;
  }
}

Добавляем анимацию в свойство animation:


animation: x 4s linear forwards,
                  y 4s cubic-bezier(0.55, 0, 0.2, -800) forwards,
                  x2 0.5s linear forwards,
                  pointOfCircle 0s linear forwards,
                  loop 3s linear forwards,
                  x3 2s linear forwards;

Добавляем подходящую задержку. Здесь она составит 7.5s:


animation-delay: 0s, 0s, 4s, 4.5s, 4.5s, 7.5s;

Окончательный результат

Заключение

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