belun.app Блог
EN

CSS cubic-bezier(): как на самом деле работают кривые плавности

Что означают четыре числа в cubic-bezier(), как построить эффекты проскока и «замаха» и когда достаточно встроенных ключевых слов ease.

Плавная изогнутая кривая движения на графике анимации на экране

ease-in-out закрывает больше случаев, чем ему обычно приписывают. Но время от времени дизайнер присылает Lottie-анимацию с отскоком, а менеджер просит, чтобы модальное окно «выпрыгивало». Тут пяти встроенных ключевых слов уже не хватает — и в дело идёт cubic-bezier(). Математика за ним проще, чем кажется по названию.

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

Две точки, четыре числа

cubic-bezier(x1, y1, x2, y2) описывает кривую между двумя фиксированными концами: она всегда начинается в точке (0, 0) и заканчивается в (1, 1). Этих двух точек нет среди аргументов функции, потому что они не могут сдвинуться: анимация всегда стартует с 0% прогресса и заканчивается на 100%. Четыре числа, которые вы задаёте, — это координаты двух контрольных точек, которые тянут кривую между этими концами.

Оси удобно читать как время и прогресс. X — прошедшее время анимации, от 0 до 1. Y — насколько далеко продвинулось анимируемое свойство, тоже в масштабе от 0 до 1, только y на самом деле этим диапазоном не ограничен. Именно отсюда берутся интересные эффекты.

Почему x ограничен, а y нет

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

У y такого ограничения нет. Ничто не мешает кривой в середине анимации поднять прогресс свойства до 120%, а затем вернуть его к 100%. Это не баг в математике — это осознанная возможность, и именно на ней строятся эффекты отскока и проскока.

Как построить проскок

Потяните вторую контрольную точку (ту, что ближе к концу кривой) выше y = 1. Что-то вроде cubic-bezier(0.34, 1.56, 0.64, 1) отправит анимируемый элемент за целевое положение, прежде чем он туда вернётся, — получается мягкий, пружинистый отскок. Я часто использую это на всплывающих уведомлениях и галочках успешного действия: обычный ease-out на их фоне ощущается плоско, а версия с проскоком ничего не стоит по весу — это всё равно одно CSS-значение.

Тот же приём работает и в начале: потяните первую контрольную точку ниже y = 0, и элемент чуть отклонится назад перед тем, как двинуться вперёд, — эффект «замаха». Аниматоры используют этот приём десятилетиями в рисованной анимации, просто здесь он выражен двумя числами вместо стопки нарисованных вручную кадров.

Пять ключевых слов, разложенных на числа

Каждое именованное ключевое слово плавности — это сокращение для конкретного вызова cubic-bezier():

  • linear — это cubic-bezier(0, 0, 1, 1): постоянная скорость, без ускорения
  • ease — это cubic-bezier(0.25, 0.1, 0.25, 1): значение по умолчанию в CSS, быстрый старт и плавная остановка
  • ease-in — это cubic-bezier(0.42, 0, 1, 1): медленный старт, без плавности в конце
  • ease-out — это cubic-bezier(0, 0, 0.58, 1): без плавности в начале, медленное завершение
  • ease-in-out — это cubic-bezier(0.42, 0, 0.58, 1): симметричные разгон и торможение

ease — это то, что получится, если написать transition вообще без timing-функции, и, честно говоря, это правильный выбор чаще, чем принято думать. За свою кривую стоит браться, когда стандартная действительно не подходит, а не по умолчанию из привычки.

Где кривая на самом деле применяется

cubic-bezier() работает везде, где CSS ожидает timing-функцию: в transition-timing-function, в animation-timing-function и в timing-функциях отдельных кадров внутри @keyframes. Модальному окну, которому нужно открываться резче, чем закрываться, не нужен JavaScript — достаточно задать одну кривую в transition-timing-function для открытия и более спокойную для закрытия.

Поиграйте с графиком в Генераторе кривых cubic-bezier, нажмите «Играть», чтобы увидеть движение вживую, и скопируйте значение, когда оно понравится.

Попробуйте инструмент

Генератор кривых cubic-bezier →