24.09.2021

Расширенная анимация CSS с использованием cubic-bezier()

Расширенная анимация CSS с внедрением cubic-bezier()

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

Несколько анимаций

Функции времени

1-ый более широко используется и знаком многим, а 2-ой менее распространен. Для этого могут быть весомые причины — объединять анимации с помощью запятых относительно проще, чем разбираться в разных доступных нам функциях синхронизации и том, что они делают. Есть одна в особенности удобная функция синхронизации, которая дает нам полный контроль над созданием пользовательской функций времени. Это cubic-bezier() и в этом посте я покажу вам ее силу и то, как ее можно использовать для сотворения чудесной анимации без особой сложности.

Начнем с базисного примера, показывающего, как мы можем перемещать мяч в определённых направлениях, к примеру, в форме бесконечности (∞):

Как видите, тут нет сложного кода — только два главных кадра и функция cubic-bezier(). И все же мы получаем достаточно сложную финальную анимацию бесконечной формы. Круто, правда? Давайте вникнем в это!

Функция cubic-bezier()

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

Расширенная анимация CSS с внедрением cubic-bezier()

Вышеупомянутая кривая определяет, как выходные данные (ось y) будут вести себя в зависимости от времени (ось x). Любая ось имеет диапазон [0, 1](либо [0% 100%]). Если у нас есть анимация, которая продолжается две секунды (2s), то:

Если мы желаем анимировать left от 5px до 20px, то:

X, время, всегда ограничено [0 1]; но Y может выходить за рамки [0 1]. Моя цель — отрегулировать P1 и P2, чтоб создать следующие кривые:

Расширенная анимация CSS с внедрением cubic-bezier()

Вы сможете подумать, что этого невозможно достичь, поэтому что, как указано в определении, P0 и P3 фиксированы (0,0) и (1,1) и это значит, что они не могут находиться на одной оси. Это правда, и мы воспользуемся некими математическими приемами, чтобы «приблизительно» их «аппроксимировать».

Параболическая кривая

Давайте начнем со последующим определением: cubic-bezier(0,1.5,1,1.5). Это дает нам последующую кривую:

Расширенная анимация CSS с внедрением cubic-bezier()

Наша цель — двигаться от (1,1) до (0,1) и делать то, что на техническом уровне невозможно. Так что попробуем построить фейковою кривую.

Ранее мы гласили, что наш диапазон равен [0 1] (либо [0% 100%]), поэтому давайте представим случай, когда 0% он очень близок к 100%. Если, к примеру, мы хотим анимировать top от 20px (0%) до, 20.1px (100%) то мы можем сказать, что изначальное и конечное состояния равны.

Хм, наш элемент вообщем не двинется? Ну, он немного двинется, потому что значение Y превышает 20.1px( 100%). Но этого недостаточно, чтоб дать нам ощутимое движение:

Давайте обновим кривую и будем использовать cubic-bezier(0,4,1,4) заместо нее. Обратите внимание на то, что наша кривая стала намного выше, чем ранее:

Расширенная анимация CSS с внедрением cubic-bezier()

Но все равно движения нет — даже если верхнее значение пересекает 3 (либо 300%). Попробуем cubic-bezier(0,20,1,20):

Расширенная анимация CSS с внедрением cubic-bezier()

Да! Он начал незначительно двигаться. Вы заметили изменение кривой каждый раз, когда мы увеличиваем значение? Это делает нашу точку (1,1) «зрительно» ближе к тому моменту (0,1) когда мы уменьшаем масштаб, чтоб увидеть полную кривую, и это уловка.

Используя cubic-bezier(0,V,1,V) где V- какое-то очень огромное значение, а начальное и конечное состояния очень близки (либо почти равны), мы можем моделировать параболическую кривую. Пример стоит тыщи слов:

Я применил «магическую» кубическую функцию Безье к анимации top, а также применил к ней линейную left. Это дает нам желаемую кривую.

Копаемся в арифметике

Для тех из вас, кто разбирается в арифметике, мы можем разбить это объяснение далее. Кубический Безье можно определить по последующей формуле:

Любая точка определяется следующим образом : P0 = (0,0), P1 = (0,V), P2 = (1,V), и P3 = (1,1). Это дает нам две функции для координат x и y:

V это наше огромное значение и t находится в границах допустимого диапазона [0 1]. Если мы разглядим наш предыдущий пример, Y(t) даст нам значение top в то время как X(t) — это время прогресса. Потом точки (X(t),Y(t)) будут определять нашу кривую.

Найдем наибольшее значение Y(t). Для этого нам необходимо найти значение t, которое нам даст Y’(t) = 0 (когда производная равна 0):

Y’(t) = 0 является квадратным уравнением. Я пропущу скучноватую часть и дам результат, который равен t = V — sqrt(V² — V).

Когда V имеет наибольшее значение, t будет равно 0.5. Означает, Y(0.5) = Max и X(0.5) будет равно 0.5. Это значит, что мы достигаем максимального значения в средней точке анимации, которая соответствует хотимой параболической кривой.

Кроме того, Y(0.5) даст нам, (1 + 6V)/8 и это позволит нам отыскать максимальное значение на основе V. И так как мы всегда будем использовать большое значение для V, мы можем упростить до 6V/8 = 0.75V.

Мы использовали V = 500 в последнем примере, потому максимальное значение будет равно 375(либо 37500%), и мы получим следующее:

Начальное состояние (0): top: 200px

Конечное состояние (1): top: 199.5px

Разница -0.5px меж 0 и 1. Назовем это повышением . Для 375(или 37500%) у нас есть уравнение 375*-0.5px = -187.5px. Наш анимационный элемент достигает top: 12.5px( 200px — 187.5px) и дает нам последующую анимацию:

Либо, выражаясь иначе:

Создадим обратную логику. Какое значение Vмы должны использовать, чтоб наш элемент стал доступным top: 0px? Анимация будет 200px → 0px → 199.5px, означает надо от -200px перейти к 0px. Наш прирост всегда равен -0.5px. Наибольшее значение будет равно 200/0.5 = 400, а это 0.75V = 400 означает V = 533.33.

Наш элемент касается верхушки! Вот цифра, которая подводит итог только что проделанной нами арифметике:

Расширенная анимация CSS с внедрением cubic-bezier()

Синусоидальная кривая

Мы воспользуемся практически тем же трюком, чтобы создать синусоидальную кривую, но с другой формулой. На этот раз мы будем использовать cubic-bezier(0.5,V,0.5,-V). Как и ранее, давайте посмотрим, как будет развиваться кривая, когда мы увеличим значение:

Расширенная анимация CSS с внедрением cubic-bezier()

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

Вот еще один пример с непрерывной анимацией — реальная синусоидальная анимация!

Математика

Давайте займемся арифметикой! Следуя той же формуле, что и ранее, мы получим следующие функции:

На этот раз нам необходимо найти минимальное и максимальное значения для Y(t). Y’(t) = 0 даст нам два решения. После решения для этого:

…мы получили:

Для огромного значения у V нас есть t’=0.211 и t»=0.789. Это значит, что Y(0.211) = Max и Y(0.789) = Min. Это также значит, что X(0.211)= 0.26 и X(0.789) = 0.74. Другими словами, мы достигаем максимума в 26% случаев и минимума в 74% случаев.

Y(0.211) равно 0.289V а Y(0.789) равно -0.289V. Мы получили эти значения с неким округлением, учитывая, что Vочень большие.

Наша синусоидальная кривая также должна пересекать ось x (либо Y(t) = 0) в половине случаев (либо X(t) = 0.5). Чтобы обосновать это, мы используем вторую производную от Y(t)- которая должна быть равна 0 и Y»(t) = 0.

Решением является 3V/(6V + 1), и для огромного значения V результатом будет 0.5. Это дает нам Y(0.5) = 0 и X(0.5) = 0.5 что подтверждает, что наша кривая пересекает точку (0.5,0).

Сейчас давайте рассмотрим предыдущий пример и попытаемся отыскать значение V, которое вернет top: 0%. У нас есть:

Начальное состояние (0): top: 50%

Конечное состояние (1): top: 49.9%

Повышение : -0.1%

Нам необходимо от -50% достичь значения top: 0%, при 0.289V*-0.1% = -50% дает нам V = 1730.10.

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

Цифра для подведения итогов расчета:

Расширенная анимация CSS с внедрением cubic-bezier()

И пример, иллюстрирующий все кривые вкупе:

Да вы видите четыре кривых! Если вы приглядитесь, вы заметите, что я использую две различные анимации: одна идет 49.9% (с шагом -0.01%), а другая 50.1% (с шагом +0.01%). Изменяя символ увеличения, мы контролируем направление кривой. Мы также можем держать под контролем другие параметры кубической кривой Безье (но V, должно оставаться огромным значением), чтобы создавать больше вариаций одних и тех же кривых.

И ниже интерактивная демонстрация:

Ворачиваясь к нашему примеру

Вернемся к нашему начальному примеру шара, движущегося в форме знака бесконечности. Я просто объединил две синусоидальные анимации, чтоб заставить их работать.

Если мы объединим то, что мы делали ранее, с концепцией множественной анимации, мы можем получить потрясающие результаты. Это опять начальный пример, на этот раз в виде интерактивной демонстрации. Измените значения и увидите чудо:

Давайте пойдем далее и добавим немного CSS Houdini. Мы можем анимировать сложное преобразования благодаря @property (но на текущий момент CSS Houdini ограничен поддержкой Chrome и Edge).

Какие картинки с его помощью можно делать? Вот несколько, что мне получилось сделать:

Расширенная анимация CSS с внедрением cubic-bezier()

А вот анимация:

И версия без CSS Houdini:

Из этих примеров можно сделать несколько выводов:

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

Положение элемента и анимация независимы. Мы можем просто разместить элемент в любом месте без необходимости настраивать анимацию.

Мы не производили расчетов. Нет огромного количества углов или значений пикселей. Нам необходимо только малое значение в ключевом кадре и огромное значение функции cubic-bezier().

Всей анимацией можно управлять, просто регулируя значение длительности.

А как насчет перехода?

Тот же способ можно использовать и со свойством CSS transition, так как он следует той же логике, когда дело касается функций времени. Это здорово, поэтому что мы можем избежать использования главных кадров при создании сложного эффекта наведения.

Вот что я сделал без главных кадров:

Марио прыгает благодаря параболической кривой. Для сотворения анимации прыжка при наведении курсора нам не необходимы были ключевые кадры. Синусоидальная кривая отлично управится со всей работой.

Вот еще одна версия Марио, на этот раз с внедрением CSS Houdini. И да, он все еще прыгает благодаря параболической кривой:

Для удобства вот более достойные внимания эффекты наведения без ключевых кадров (снова же, только для Chrome и Edge):

Вот и всё!

Сейчас у вас есть несколько волшебных кривых cubic-bezier() и математика, стоящая за ними. Преимущество, естественно же, заключается в том, что такие пользовательские функции синхронизации позволяют нам создавать фантастические анимации без сложных главных кадров, к которым мы обычно стремимся.

Я понимаю, что не все разбираются в арифметике, и это нормально. Есть инструменты, которые имеют возможность помочь, например Ceaser Мэтью Лейна, который позволяет вам перетаскивать точки кривой, чтоб получить то, что вам нужно. И, если вы еще не добавили его в закладки, cubic-bezier.com — еще один нужный ресурс. Если вы хотите поиграть с кубиком Безье за пределами мира CSS, я рекомендую desmos, где вы сможете увидеть некоторые математические формулы.

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

По материалам webformyself.com

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *