Функция плавности (easing) определяет характер изменения значения анимации во времени. Вместо линейного перехода от начального состояния к конечному используется математическая кривая, задающая ускорение и замедление. В Velocity.js это один из ключевых механизмов управления ощущением анимации.
В основе любой easing-функции лежит отображение диапазона времени [0, 1] → [0, 1], где входное значение — прогресс анимации, а выходное — скорректированное значение, влияющее на интерполяцию свойств.
Velocity.js поддерживает несколько уровней определения функций плавности:
"ease",
"ease-in", "ease-out")Внутренне Velocity нормализует easing до функции вида:
function easing(t) {
return value;
}
где:
t — прогресс анимации от 0 до 1value — модифицированный прогрессПользовательская функция плавности в Velocity.js представляет собой чистую функцию, принимающую числовой параметр и возвращающую числовое значение.
function customEasing(progress) {
return progress;
}
При таком определении поведение эквивалентно линейной анимации.
Любые модификации формы кривой достигаются изменением зависимости между входом и выходом.
Velocity.js позволяет расширять набор easing-функций через глобальный объект:
Velocity.Easings.myEasing = function (t) {
return t;
};
После регистрации имя используется как строковый идентификатор:
Velocity(element, { opacity: 1 }, { duration: 1000, easing: "myEasing" });
Аналогичная регистрация в jQuery-совместимом синтаксисе:
$.Velocity.Easings.myEasing = function (t) {
return t;
};
Простейшие модификации создаются через геометрические преобразования
функции t.
Velocity.Easings.accelerate = function (t) {
return t * t;
};
Поведение:
Velocity.Easings.decelerate = function (t) {
return 1 - Math.pow(1 - t, 2);
};
Поведение:
Velocity.Easings.smooth = function (t) {
return t < 0.5
? 2 * t * t
: 1 - Math.pow(-2 * t + 2, 2) / 2;
};
Такой тип кривой часто используется для интерфейсных переходов, где требуется симметричное поведение ускорения и замедления.
Полиномы позволяют задавать более сложные формы движения.
Velocity.Easings.cubicIn = function (t) {
return t * t * t;
};
Velocity.Easings.cubicOut = function (t) {
return 1 - Math.pow(1 - t, 3);
};
Чем выше степень полинома, тем более выраженной становится нелинейность движения.
Эластичное поведение моделирует колебания вокруг конечного значения. Такие функции используются для создания «живых» интерфейсных эффектов.
Velocity.Easings.elastic = function (t) {
return Math.sin(-13 * (Math.PI / 2) * (t + 1)) * Math.pow(2, -10 * t) + 1;
};
Характерные особенности:
Bounce-эффект имитирует падение и отскок объекта. Реализация обычно строится через кусочную функцию.
Velocity.Easings.bounce = function (t) {
if (t < 1 / 2.75) {
return 7.5625 * t * t;
} else if (t < 2 / 2.75) {
return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
} else if (t < 2.5 / 2.75) {
return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
} else {
return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
}
};
Подобные функции активно применяются для визуальных акцентов в интерфейсе.
Для корректной работы easing-функции важно соблюдать нормализацию входного значения:
t < 0 — приводится к 0t > 1 — приводится к 1Иногда это делается внутри функции:
function clamp(t) {
return Math.max(0, Math.min(1, t));
}
Применение:
Velocity.Easings.safeEase = function (t) {
t = Math.max(0, Math.min(1, t));
return t * t;
};
Сложные кривые могут быть построены через композицию функций.
Velocity.Easings.composite = function (t) {
function easeIn(x) {
return x * x;
}
function easeOut(x) {
return 1 - Math.pow(1 - x, 2);
}
return t < 0.5
? easeIn(t * 2) / 2
: 0.5 + easeOut((t - 0.5) * 2) / 2;
};
Такой подход позволяет разносить поведение по сегментам времени.
Функции могут быть параметризованы через замыкания, что позволяет создавать семейства кривых.
function createPowerEase(power) {
return function (t) {
return Math.pow(t, power);
};
}
Velocity.Easings.easeInQuad = createPowerEase(2);
Velocity.Easings.easeInQuart = createPowerEase(4);
Подобный подход снижает дублирование кода и упрощает масштабирование набора анимаций.
Хотя Velocity.js не всегда напрямую интерпретирует CSS cubic-bezier, математическая модель может быть реализована вручную:
Velocity.Easings.cubicBezier = function (t) {
const c1 = 0.42;
const c2 = 0.0;
const c3 = 0.58;
const c4 = 1.0;
return (
Math.pow(1 - t, 3) * 0 +
3 * Math.pow(1 - t, 2) * t * c1 +
3 * (1 - t) * Math.pow(t, 2) * c3 +
Math.pow(t, 3) * 1
);
};
Такие функции позволяют приближать поведение CSS-анимаций внутри JavaScript-движка.
Поскольку easing вызывается на каждом кадре анимации, важна минимизация вычислений:
Оптимизированный вариант:
const sin = Math.sin;
const pow = Math.pow;
Velocity.Easings.fastElastic = function (t) {
return sin(-10 * t) * pow(2, -5 * t) + 1;
};
Некоторые easing-функции возвращают значения меньше 0 или больше 1. Это используется для:
Пример:
Velocity.Easings.overshoot = function (t) {
const s = 1.70158;
return t * t * ((s + 1) * t - s);
};
Такие функции расширяют визуальную динамику интерфейса.
В Velocity.js easing применяется на уровне каждого вызова анимации:
Velocity(element, {
translateX: "200px",
opacity: 0
}, {
duration: 800,
easing: "smooth"
});
При последовательных анимациях каждая фаза может использовать собственную кривую:
Velocity(element, "fadeIn", { easing: "cubicIn" })
.then(() => Velocity(element, "fadeOut", { easing: "bounce" }));
При масштабных проектах набор функций плавности часто структурируется как библиотека:
const Easings = {
linear: function (t) { return t; },
smooth: function (t) {
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
},
bounce: function (t) {
if (t < 0.5) return 7.5625 * t * t;
return 1 - 7.5625 * (1 - t) * (1 - t);
}
};
Object.assign(Velocity.Easings, Easings);
Такая структура упрощает повторное использование и тестирование поведения анимаций.