Взаимодействие через hover в контексте Lottie Web строится на
управлении жизненным циклом анимации через API lottie-web и
DOM-события мыши. Основная идея заключается в том, чтобы отключить
автоматическое воспроизведение и полностью делегировать управление
состоянием анимации событиям mouseenter,
mouseleave, mouseover,
mouseout.
Инициализация анимации выполняется с отключёнными автоматическими режимами:
const animation = lottie.loadAnimation({
container: document.querySelector('.icon'),
renderer: 'svg',
loop: false,
autoplay: false,
path: '/animations/icon.json'
});
Ключевое значение имеют параметры:
Такая конфигурация создаёт управляемую анимационную сущность, готовую к внешним триггерам.
Поведение hover реализуется через стандартные DOM-события. Наиболее
устойчивым вариантом является использование mouseenter и
mouseleave, поскольку они не всплывают и не вызывают
повторных срабатываний при переходе между дочерними элементами.
const container = document.querySelector('.icon');
container.addEventListener('mouseenter', () => {
animation.goToAndPlay(0, true);
});
container.addEventListener('mouseleave', () => {
animation.stop();
});
В этом сценарии:
Более гибкий вариант предполагает использование паузы вместо полной остановки:
container.addEventListener('mouseenter', () => {
animation.play();
});
container.addEventListener('mouseleave', () => {
animation.pause();
});
Такой подход сохраняет текущее состояние кадра и позволяет продолжить воспроизведение с точки остановки.
Наиболее контролируемый способ реализации hover-эффектов в Lottie Web — использование сегментов анимации. Сегменты позволяют разделить композицию на логические части: вступление, активное состояние и возврат.
container.addEventListener('mouseenter', () => {
animation.playSegments([0, 30], true);
});
container.addEventListener('mouseleave', () => {
animation.playSegments([30, 60], true);
});
Сегментный подход обеспечивает:
При использовании true во втором параметре происходит
немедленный перезапуск сегмента.
В некоторых интерфейсах требуется, чтобы анимация проигрывалась в
цикле только при наведении. Для этого используется динамическое
переключение режима loop.
container.addEventListener('mouseenter', () => {
animation.loop = true;
animation.play();
});
container.addEventListener('mouseleave', () => {
animation.loop = false;
animation.stop();
});
Альтернативный вариант — использование сегментов с бесконечным повторением последнего состояния:
container.addEventListener('mouseenter', () => {
animation.playSegments([0, 45], true);
animation.loop = true;
});
container.addEventListener('mouseleave', () => {
animation.loop = false;
animation.playSegments([45, 60], true);
});
Hover-анимации часто используют эффект «вперёд-назад». Это реализуется через управление направлением проигрывания.
container.addEventListener('mouseenter', () => {
animation.setDirection(1);
animation.play();
});
container.addEventListener('mouseleave', () => {
animation.setDirection(-1);
animation.play();
});
Такой подход требует, чтобы анимация была спроектирована симметрично: обратный ход должен визуально возвращать объект в исходное состояние.
При частом входе и выходе курсора возникает проблема прерывания кадрового потока. Для стабилизации используется принудительное управление текущим кадром:
container.addEventListener('mouseenter', () => {
animation.stop();
animation.goToAndPlay(0, true);
});
container.addEventListener('mouseleave', () => {
animation.stop();
});
Дополнительная стабилизация достигается блокировкой повторных запусков:
let isPlaying = false;
container.addEventListener('mouseenter', () => {
if (isPlaying) return;
isPlaying = true;
animation.goToAndPlay(0, true);
});
animation.addEventListener('complete', () => {
isPlaying = false;
});
В интерфейсных компонентах часто требуется не полное проигрывание, а демонстрация микровзаимодействия. Для этого используется ограниченный диапазон кадров.
container.addEventListener('mouseenter', () => {
animation.playSegments([10, 25], true);
});
container.addEventListener('mouseleave', () => {
animation.playSegments([25, 40], true);
});
Такая техника применяется для:
При наличии множества элементов с Lottie-анимацией важно избегать глобального состояния. Каждая анимация должна быть независимой сущностью.
document.querySelectorAll('.lottie-hover').forEach((el) => {
const anim = lottie.loadAnimation({
container: el,
renderer: 'svg',
loop: false,
autoplay: false,
path: el.dataset.path
});
el.addEventListener('mouseenter', () => {
anim.goToAndPlay(0, true);
});
el.addEventListener('mouseleave', () => {
anim.stop();
});
});
Такая структура обеспечивает:
Hover-анимации могут вызывать частые перерисовки, особенно при использовании SVG-рендерера. Для минимизации нагрузки применяются следующие подходы:
rendererSettings с избыточной
детализациейrequestAnimationFrame при сложной логике
переключенияПример предзагрузки:
const animationDataCache = {};
fetch('/animations/icon.json')
.then(res => res.json())
.then(data => {
animationDataCache.icon = data;
});
Hover-воспроизведение часто связывается с логикой компонентов. Анимация становится визуальным отражением состояния интерфейса.
function setActiveState(el, anim) {
el.classList.add('active');
anim.setSpeed(1.2);
anim.play();
}
function setInactiveState(el, anim) {
el.classList.remove('active');
anim.stop();
}
Использование скорости позволяет дополнительно дифференцировать состояния без изменения структуры JSON-анимации.
В сложных интерфейсах hover может запускать цепочку анимаций:
container.addEventListener('mouseenter', () => {
animation.playSegments([0, 20], true);
setTimeout(() => {
animation.playSegments([20, 40], true);
}, 200);
});
Такая последовательность создаёт ощущение многослойной реакции интерфейса.
Контроль финального состояния важен для предотвращения визуальных разрывов.
container.addEventListener('mouseleave', () => {
animation.playSegments([40, 60], true);
});
animation.addEventListener('complete', () => {
animation.goToAndStop(0, true);
});
Фиксация состояния после завершения позволяет избежать накопления промежуточных кадров и обеспечивает предсказуемое поведение при следующем наведении.