Обратная анимация в Velocity.js строится вокруг идеи повторного
применения анимационного перехода с инвертированными значениями свойств
или восстановления предыдущего состояния элемента. В отличие от
классического CSS-подхода с transition, где браузер
самостоятельно интерполирует состояния, Velocity.js оперирует явными
числовыми параметрами и хранит управление временем, easing и очередями
выполнения.
Ключевой принцип: любая анимация представляет собой функцию перехода между двумя наборами свойств, и «reverse» фактически означает обмен начального и конечного состояния либо повторное воспроизведение ранее сохранённого состояния в обратном направлении.
Самый прямолинейный способ реализации обратной анимации заключается в ручной инверсии параметров.
Если исходная анимация:
Velocity(element, { opacity: 1, translateY: 0 }, { duration: 300 });
то обратная логика формируется явно:
Velocity(element, { opacity: 0, translateY: 20 }, { duration: 300 });
Такой подход применим в случаях, когда начальные и конечные значения заранее известны и не зависят от текущего состояния DOM.
Более устойчивый вариант — считывание текущих вычисленных значений перед запуском обратного перехода:
const currentOpacity = parseFloat(getComputedStyle(element).opacity);
Velocity(element, { opacity: currentOpacity < 0.5 ? 1 : 0 }, { duration: 300 });
Подобная схема используется в UI-компонентах, где состояние не фиксировано, а вычисляется динамически.
При сложных анимациях требуется явное сохранение исходных значений, поскольку Velocity.js не всегда может восстановить их автоматически после трансформаций.
const state = {
opacity: getComputedStyle(element).opacity,
transform: element.style.transform
};
Анимация вперёд:
Velocity(element, {
opacity: 0,
translateY: -30
}, {
duration: 400
});
Обратный переход:
Velocity(element, {
opacity: state.opacity,
translateY: 0
}, {
duration: 400
});
Такой подход особенно важен при работе с transform,
поскольку составные трансформации могут теряться при последовательных
вызовах.
Velocity.js поддерживает внутреннюю очередь анимаций, что позволяет строить обратные последовательности как зеркальные цепочки.
Прямая цепочка:
Velocity(element, { translateX: 100 }, { duration: 200 })
.velocity({ translateY: 50 }, { duration: 200 })
.velocity({ opacity: 0 }, { duration: 200 });
Обратная цепочка должна учитывать порядок выполнения:
Velocity(element, { opacity: 1 }, { duration: 200 })
.velocity({ translateY: 0 }, { duration: 200 })
.velocity({ translateX: 0 }, { duration: 200 });
Ключевая особенность: очереди Velocity выполняются последовательно, поэтому обратная анимация всегда строится в обратном порядке шагов, а не только значений.
Velocity.js позволяет управлять активными анимациями через остановку текущего процесса и запуск нового перехода от текущего состояния.
Velocity(element, "stop");
Velocity(element, {
opacity: 0,
translateY: 30
}, {
duration: 300
});
Такой механизм используется для «резкого разворота» интерфейсных состояний, например при мгновенном закрытии панели, уже находящейся в процессе открытия.
Velocity UI Pack добавляет набор готовых переходов и поддерживает концепцию reverse для определённых эффектов.
Типичный сценарий:
Velocity(element, "transition.slideUpIn", { duration: 300 });
Velocity(element, "reverse");
Команда reverse в UI Pack работает как переключатель состояния последнего transition-анимационного эффекта, восстанавливая предыдущее положение элемента.
Особенность заключается в том, что reverse работает только для анимаций, созданных через UI Pack transitions, поскольку они сохраняют внутреннюю мета-информацию о начальных значениях.
Velocity.js позволяет повторно запускать анимацию с изменением направления логики без использования UI Pack.
Пример универсального tween-паттерна:
function animateIn(el) {
Velocity(el, {
opacity: 1,
scale: 1
}, { duration: 250 });
}
function animateOut(el) {
Velocity(el, {
opacity: 0,
scale: 0.8
}, { duration: 250 });
}
Обратная логика здесь не зависит от состояния Velocity, а полностью контролируется внешними функциями, что упрощает поддержку в крупных интерфейсах.
Сложности возникают при комбинировании нескольких трансформаций:
Velocity.js хранит трансформации как строку transform,
что делает частичную инверсию нетривиальной задачей.
Пример корректного хранения:
const initial = element.style.transform;
Velocity(element, {
translateX: 200,
rotateZ: 45
}, { duration: 400 });
Обратное восстановление:
element.style.transform = initial;
Такой подход часто надёжнее, чем попытка математически инвертировать каждый параметр отдельно.
Velocity.js поддерживает stagger-эффекты, где элементы анимируются с задержкой. При обратной анимации важно инвертировать не только свойства, но и порядок элементов.
Прямая последовательность:
Velocity(elements, { opacity: 1, translateY: 0 }, {
stagger: 80,
duration: 200
});
Обратная:
Velocity(elements.reverse(), { opacity: 0, translateY: 20 }, {
stagger: 80,
duration: 200
});
Инверсия массива элементов играет ключевую роль, иначе визуальный эффект не будет зеркальным.
В интерфейсных компонентах reverse-анимация часто связана с логическим состоянием:
let isOpen = false;
function toggle() {
if (isOpen) {
Velocity(panel, { height: 0, opacity: 0 }, { duration: 300 });
} else {
Velocity(panel, { height: 300, opacity: 1 }, { duration: 300 });
}
isOpen = !isOpen;
}
Такая модель исключает необходимость хранения промежуточных состояний Velocity и делает поведение предсказуемым.
Velocity.js не всегда требует явного reverse-метода: достаточно прервать текущую анимацию и запустить новую с инвертированными параметрами.
Velocity(element, "stop", true);
Velocity(element, {
translateY: 0,
opacity: 1
}, {
duration: 300
});
Флаг true очищает очередь анимаций, предотвращая
наложение переходов и артефакты состояния.
В интерфейсах с множеством вложенных компонентов reverse-анимации применяются в следующих сценариях:
Типовой паттерн модального окна:
function openModal() {
Velocity(modal, { opacity: 1, scale: 1 }, { duration: 250 });
}
function closeModal() {
Velocity(modal, { opacity: 0, scale: 0.9 }, { duration: 200 });
}
Здесь reverse не требует симметрии параметров, поскольку закрытие использует упрощённую кривую движения для ускорения реакции интерфейса.
Easing-функции не всегда симметричны при инверсии анимаций. Например:
ease-in при открытииease-out при закрытииVelocity(el, { opacity: 1 }, {
duration: 300,
easing: "easeOutQuad"
});
Velocity(el, { opacity: 0 }, {
duration: 200,
easing: "easeInQuad"
});
Такой подход создаёт визуальную согласованность: появление воспринимается плавно, исчезновение — быстрее и более «решительно».
Velocity.js позволяет строить сложные обратные сценарии с задержками:
Velocity(element, { opacity: 0 }, { duration: 200 })
.velocity({ translateY: 20 }, { duration: 200, delay: 50 })
.velocity({ scale: 0.8 }, { duration: 200 });
Обратный сценарий требует не только инверсии значений, но и пересмотра задержек, чтобы сохранить естественность движения.