Интерактивные переходы — это анимации, которые реагируют на действия пользователя: наведение курсора, клики, прокрутку, ввод данных. В контексте библиотеки anime.js такие переходы строятся на сочетании событий DOM и анимационных конфигураций.
Ключевая идея — связать событие и анимацию, обеспечив плавную реакцию интерфейса на действия.
Основные типы взаимодействий:
Типичный сценарий включает три элемента:
const button = document.querySelector('.btn');
button.addEventListener('mouseenter', () => {
anime({
targets: button,
scale: 1.1,
duration: 300,
easing: 'easeOutQuad'
});
});
button.addEventListener('mouseleave', () => {
anime({
targets: button,
scale: 1,
duration: 300,
easing: 'easeOutQuad'
});
});
Hover-анимации используются для создания мгновенной визуальной обратной связи.
anime({
targets: '.card',
backgroundColor: '#ffcc00',
scale: 1.05,
duration: 400,
easing: 'easeOutCubic',
autoplay: false
});
Для интерактивности необходимо управлять запуском:
const cards = document.querySelectorAll('.card');
cards.forEach(card => {
const animation = anime({
targets: card,
scale: 1.05,
duration: 300,
autoplay: false
});
card.addEventListener('mouseenter', animation.play);
card.addEventListener('mouseleave', animation.reverse);
});
Особенность: метод reverse() позволяет
воспроизводить анимацию в обратном направлении, что упрощает управление
состояниями.
Клик — основной триггер для сложных переходов.
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
anime.timeline()
.add({
targets: btn,
scale: 0.9,
duration: 100
})
.add({
targets: btn,
scale: 1,
duration: 200,
easing: 'easeOutElastic(1, .5)'
});
});
let active = false;
btn.addEventListener('click', () => {
active = !active;
anime({
targets: '.menu',
translateX: active ? 0 : '-100%',
duration: 500,
easing: 'easeInOutQuad'
});
});
Ключевой момент: хранение состояния вне анимации позволяет управлять интерфейсом предсказуемо.
anime.js не имеет встроенного scroll-движка, но легко интегрируется с событиями прокрутки.
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
anime({
targets: '.header',
translateY: scrollY > 100 ? -80 : 0,
duration: 300,
easing: 'easeOutQuad'
});
});
window.addEventListener('scroll', () => {
const progress = window.scrollY / 500;
anime.set('.box', {
translateX: progress * 300
});
});
anime.set() позволяет мгновенно обновлять значения без анимации — важно для синхронизации с прокруткой.
Интерактивные интерфейсы часто требуют анимации между двумя состояниями элемента.
const toggle = document.querySelector('.toggle');
const panel = document.querySelector('.panel');
let open = false;
toggle.addEventListener('click', () => {
open = !open;
anime({
targets: panel,
height: open ? 200 : 0,
opacity: open ? 1 : 0,
duration: 400,
easing: 'easeInOutQuad'
});
});
const contentHeight = panel.scrollHeight;
anime({
targets: panel,
height: open ? contentHeight : 0
});
Timeline позволяет строить последовательные и синхронизированные анимации.
const tl = anime.timeline({
autoplay: false
});
tl.add({
targets: '.overlay',
opacity: [0, 1],
duration: 300
}).add({
targets: '.modal',
translateY: [-50, 0],
opacity: [0, 1],
duration: 400
}, '-=200');
Запуск по событию:
document.querySelector('.open').addEventListener('click', () => {
tl.play();
});
Закрытие:
document.querySelector('.close').addEventListener('click', () => {
tl.reverse();
});
Преимущество: единый контроль над всей цепочкой анимаций.
anime.js поддерживает динамические значения.
anime({
targets: '.item',
translateX: (el, i) => i * 50,
delay: (el, i) => i * 100
});
document.addEventListener('mousemove', (e) => {
anime({
targets: '.cursor',
left: e.clientX,
top: e.clientY,
duration: 100,
easing: 'linear'
});
});
Для drag-интеракций используется комбинация событий мыши.
const box = document.querySelector('.box');
let isDragging = false;
box.addEventListener('mousedown', () => {
isDragging = true;
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
anime.set(box, {
translateX: e.clientX,
translateY: e.clientY
});
});
Ключевые параметры:
easing: 'easeOutElastic(1, .5)'
easing: 'easeInOutQuad'
easing: 'cubicBezier(.5, .05, .1, .3)'
Рекомендации:
Интерактивные анимации могут вызывать лаги при неправильной реализации.
transform вместо
top/leftanime.set() для мгновенных обновленийlet ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
// анимация
ticking = false;
});
ticking = true;
}
});
Часть эффектов удобнее реализовать через CSS, а anime.js использовать для логики.
.box {
transition: background-color 0.3s;
}
box.addEventListener('mouseenter', () => {
box.style.backgroundColor = 'red';
});
anime.js добавляет:
Хорошая практика — разделение:
function openMenu() {
return anime({
targets: '.menu',
translateX: 0
});
}
function closeMenu() {
return anime({
targets: '.menu',
translateX: '-100%'
});
}
Такой подход:
Интерактивные переходы особенно эффективны в:
anime.js обеспечивает:
За счёт этого интерактивные переходы становятся не просто визуальным эффектом, а инструментом улучшения пользовательского опыта и навигации.